为什么这些同步方法不断给我不同的输出?
Why do these synchronized methods keep giving me different outputs?
我需要这些可以访问相同数据的线程同时执行而不会相互混淆,所以我一直在尝试使用同步方法而不是使用 Thread.join()
。问题是我根本看不到任何变化,它一直给我使用它们之前的相同结果。我什至不知道我到底做错了什么,synchronized
方法应该阻止其他同步方法在完成之前执行,对吗?希望你能给我一些线索。
public class ThreadSync{
public static void main(String[] args) throws InterruptedException {
//if execute properly
//output can't be other than 0
while(true) {
ChangeValue counter = new ChangeValue();
Threads t = new Threads(counter,"up");
Threads t2 = new Threads(counter,"down");
Threads t3 = new Threads(counter,"print");
t.start();
t2.start();
t3.start();
}
}
}
class Threads extends Thread{
Threads(ChangeValue obj, String act){
counter = obj;
action = act;
}
@Override
public void run() {
switch(action) {
case ("up"): counter.up(); break;
case ("down"): counter.down(); break;
case ("print"): counter.print(); break;
}
}
ChangeValue counter;
String action;
}
class ChangeValue{
public synchronized void up() { value++; }
public synchronized void down() { value--; }
public synchronized void print() { System.out.println(value); }
public int value = 0;
}
同步只是保证方法不会同时执行。但是,它不保证任何执行顺序。
您需要确保 print()
不会在其他线程终止之前执行。这可以通过连接线程来实现。为此,执行
t.join();
t2.join();
在启动打印线程之前或在执行其逻辑之前。
请注意,同步仍然是明智的,因为它确保增量和减量操作以原子方式执行。即执行count++
时读、自增、写count
是一次性执行的
(另请参阅:Why is i++ not atomic?)。因此它阻止了以下执行顺序:
- [线程“up”]:用值
0
加载 count
- [线程“向下”]:用值
0
加载 count
- [线程“向上”]:将
count
增加到 1
- [线程“向下”]:将
count
递减为 -1
- [线程“向上”]:存储
count
值为 1
- [线程“向下”]:将
count
存储为值 -1
(这是数据库术语中的“丢失更新”。)
synchronized
阻止您的线程同时访问该字段,但当然它不能保证线程执行的顺序。
例如,如果纯属偶然,“Up”线程首先执行,“Print”线程第二,“Down”线程最后执行,则输出将为 1,即使在所有线程完成后计数器值为 0。
我需要这些可以访问相同数据的线程同时执行而不会相互混淆,所以我一直在尝试使用同步方法而不是使用 Thread.join()
。问题是我根本看不到任何变化,它一直给我使用它们之前的相同结果。我什至不知道我到底做错了什么,synchronized
方法应该阻止其他同步方法在完成之前执行,对吗?希望你能给我一些线索。
public class ThreadSync{
public static void main(String[] args) throws InterruptedException {
//if execute properly
//output can't be other than 0
while(true) {
ChangeValue counter = new ChangeValue();
Threads t = new Threads(counter,"up");
Threads t2 = new Threads(counter,"down");
Threads t3 = new Threads(counter,"print");
t.start();
t2.start();
t3.start();
}
}
}
class Threads extends Thread{
Threads(ChangeValue obj, String act){
counter = obj;
action = act;
}
@Override
public void run() {
switch(action) {
case ("up"): counter.up(); break;
case ("down"): counter.down(); break;
case ("print"): counter.print(); break;
}
}
ChangeValue counter;
String action;
}
class ChangeValue{
public synchronized void up() { value++; }
public synchronized void down() { value--; }
public synchronized void print() { System.out.println(value); }
public int value = 0;
}
同步只是保证方法不会同时执行。但是,它不保证任何执行顺序。
您需要确保 print()
不会在其他线程终止之前执行。这可以通过连接线程来实现。为此,执行
t.join();
t2.join();
在启动打印线程之前或在执行其逻辑之前。
请注意,同步仍然是明智的,因为它确保增量和减量操作以原子方式执行。即执行count++
时读、自增、写count
是一次性执行的
(另请参阅:Why is i++ not atomic?)。因此它阻止了以下执行顺序:
- [线程“up”]:用值
0
加载 - [线程“向下”]:用值
0
加载 - [线程“向上”]:将
count
增加到1
- [线程“向下”]:将
count
递减为-1
- [线程“向上”]:存储
count
值为1
- [线程“向下”]:将
count
存储为值-1
count
count
(这是数据库术语中的“丢失更新”。)
synchronized
阻止您的线程同时访问该字段,但当然它不能保证线程执行的顺序。
例如,如果纯属偶然,“Up”线程首先执行,“Print”线程第二,“Down”线程最后执行,则输出将为 1,即使在所有线程完成后计数器值为 0。