我正在尝试运行多个线程。我显然已经获得了竞争条件,并且能够按如下方式解决它:
final Data data = new Data();
for (int i = 0; i < numberOfThreads; i++) {
final Thread thread = new Thread(new Runnable() {
@Override
public void run() {
//using this sync block to stop the race condition
synchronized (data){
final int value = data.getValue();
data.setValue(value + 1);
}
}
});
thread.start();
}
但我不想在这个块上进行同步,而是希望在Data类中处理它。所以我删除了上面的同步块,而是在Data类中同步get和set方法,如下所示,但这仍然会导致竞争条件。为什么这个问题即使我已经同步了?
public class Data {
private int value;
public synchronized int getValue(){
return this.value;
}
public synchronized void setValue(int num){
this.value = num;
}
}
答案 0 :(得分:4)
因为你没有。您同步了其中任何一个,因此两个线程无法同时执行这些方法,但是一个线程可以执行getValue()
然后完成getValue()
,在它进入setValue()
之前,另一个线程轮到它了致电getValue()
这是完全合法的,也是你的竞争条件。
顺便说一下。为了防止Data
成为你的整个班级,AtomicInteger
将是相同的,但做得恰当。你在那里。 G。有一个incrementAndGet()
方法可以在一个同步块中执行读写操作,这是您案例的基本点。
答案 1 :(得分:2)
将synchronized
添加到各个方法类似于执行此类操作
final Data data = new Data();
for (int i = 0; i < numberOfThreads; i++) {
final Thread thread = new Thread(new Runnable() {
@Override
public void run() {
synchronized (data){
final int value = data.getValue();
}
synchronized (data){
data.setValue(value + 1);
}
}
});
thread.start();
}
线程可能非常明显地卡在get和set之间。要解决此问题,您需要向完成Data
任务的value + 1
类添加新的同步方法,或者在synchronized
块中包含两行,就像在您的代码。
答案 2 :(得分:1)
首先,在 String res="";
Integer opt=Integer.parseInt(JOptionPane.showInputDialog("How many numbers do you need?"));
for (int i=0; i<opt; i++) {
String numbers=JOptionPane.showInputDialog("Add your numbers");
res += numbers;
}
String reversedString = new StringBuilder(res).reverse().toString();
JOptionPane.showMessageDialog(null,"Your numbers are "+ reversedString);
班级中Data
应该是value
。
关于你提到的问题;你不能像你一样改变代码。 因为在你改变它的方式可能会发生以下情况:
1)
volatile
中value
为Data
2)
0
读取Thread 0
(读取value
)3)
0
读取Thread 1
(读取value
)4)
0
递增Thread 1
并将新值写入value
(写Data.value
)5)
1
递增Thread 0
并将新值写入value
(写Data.value
)
此处的问题是,在步骤5)中编写了1
,因为1
因Thread 0
读取Thread 1
而不知道value
已经增加Thread 0
value
。
答案 3 :(得分:0)
您在方法级别添加了synchronized。所以一个线程可以调用getValue(),一个可以调用setValue()。您可以完全删除同步并将私有“值”成员的类型更改为AutomicInteger。然后在该类中使用线程安全方法。