开门见山,我已经编写了一个代码来测试 java 中的并发性,使用同步方法:
代码:
public class ThreadTraining {
public static class Value {
private static int value;
public static synchronized void Add() {
value++;
}
public static synchronized void Sub() {
value--;
}
public static synchronized int Get() {
return value;
}
}
public static class AddT implements Runnable {
public static String name;
public AddT(String n) {
name = n;
}
@Override
public void run() {
while (Value.Get() < 100) {
int prev = Value.Get();
Value.Add();
System.out.println("[" + name + "] - changed value from " + prev + " to " + Value.Get());
}
}
}
public static class SubT implements Runnable {
public static String name;
public SubT(String n) {
name = n;
}
@Override
public void run() {
while (Value.Get() > (-100)) {
int prev = Value.Get();
Value.Sub();
System.out.println("[" + name + "] - changed value from " + prev + " to " + Value.Get());
}
}
}
public static void main(String[] args) {
Thread threads[] = new Thread[3];
for (int i = 0; i < 4; i++) {
if (i % 2 == 0) {
threads[i] = new Thread(new AddT("Adder - Thread #" + i));
} else {
threads[i] = new Thread(new SubT("Subtractor - Thread #" + i));
}
threads[i].start();
}
}
}
尽管 “对同一对象的同步方法的两次调用不可能交错”,但这段代码很难执行。(来源:Oracle's concurrency tutorial - Synchronized methods),给出不可靠的输出,例如:(注意,输出中的任何非模式更改都在“...”行之间表示,不仅仅是不可靠的行为 )
-----[Thread #0 - Adder] has been created!
=====[Thread #0 - Adder] has been started!
-----[Thread #1 - Subtractor] has been created!
[Thread #0 - Adder] - changed value from 0 to 1
[Thread #0 - Adder] - changed value from 1 to 2
[Thread #0 - Adder] - changed value from 2 to 3
...\*goes on, adding as expected, for some lines*\
[Thread #0 - Adder] - changed value from 83 to 84
[Thread #0 - Adder] - changed value from 84 to 85
-----[Thread #2 - Adder] has been created!
=====[Thread #1 - Subtractor] has been started!
[Thread #0 - Adder] - changed value from 85 to 86
[Thread #1 - Subtractor] - changed value from 86 to 85
[Thread #1 - Subtractor] - changed value from 86 to 85
[Thread #1 - Subtractor] - changed value from 85 to 84
...\*goes on, subtracting as expected, for some lines*\
[Thread #1 - Subtractor] - changed value from -98 to -99
[Thread #1 - Subtractor] - changed value from -99 to -100 \*This thread ends here, as it reaches the state where (value>(-100))==false*\
=====[Thread #2 - Adder] has been started!
[Thread #2 - Adder] - changed value from -100 to -99
[Thread #2 - Adder] - changed value from -99 to -98
[Thread #2 - Adder] - changed value from -98 to -97
...\*goes on as expected...*\
[Thread #2 - Adder] - changed value from -67 to -66
[Thread #2 - Adder] - changed value from -66 to -65
-----[Thread #3 - Subtractor] has been created!
=====[Thread #3 - Subtractor] has been started!
[Thread #3 - Subtractor] - changed value from -65 to -66
[Thread #3 - Subtractor] - changed value from -66 to -67
...\*goes on as expected...*\
[Thread #3 - Subtractor] - changed value from -71 to -72
[Thread #3 - Subtractor] - changed value from -72 to -73 \*NOTE: From -73 it goes to -74, without a Subtractor-action in between! WTF???*\
[Thread #2 - Adder] - changed value from -74 to -73
[Thread #2 - Adder] - changed value from -73 to -72
...\*goes on as expected...*\
[Thread #2 - Adder] - changed value from 98 to 99
[Thread #2 - Adder] - changed value from 99 to 100 \*This adder ends here, adder thread #0 probably ends after next line...but not before doing something crazy!*\
[Thread #0 - Adder] - changed value from 85 to 86 \*What the hell are these values doing here? Oh wait, next lines is...*\
[Thread #3 - Subtractor] - changed value from -73 to -47\*...Holy mother of god!*\
[Thread #3 - Subtractor] - changed value from 100 to 99
[Thread #3 - Subtractor] - changed value from 99 to 98
...
[Thread #3 - Subtractor] - changed value from -98 to -99
[Thread #3 - Subtractor] - changed value from -99 to -100 \*The logical nightmare is finally over.*\
使用synchronized方法不靠谱吗?还是执行错误? (如果是,那是什么问题?如何解决?)
最佳答案
您的实现有点不对劲。 ‘Get’、‘Add’和‘Sub’都被锁定,但是你的‘Get’和你的加减法之间有一个间隙。刚刚执行“获取”的线程可以在那个间隙休息一下,其他人会更改该值。如果您希望多个方法调用都作为单个操作发生,则需要在比单个方法“更大”的事物上进行同步。
synchronized (Value.class) {
int prev = Value.Get();
Value.Add();
System.out.println("[" + name + "] - changed value from " + prev + " to " + Value.Get());
}
请注意,这仍然存在一个问题,当您输入时 <100 可能仍然不正确,因此您应该重新检查它。 (当然,锁定 Class 对象并不是您通常希望在“真实”代码中执行的操作 :))
关于java - 在java中,使用synchronized方法能不靠谱吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10606063/