为什么这些同步方法总是给我不同的输出?

Mik*_*DvP 2 java concurrency multithreading thread-safety java-threads

我需要这个可以访问相同数据的线程同时执行而不会相互混淆,所以Thread.join()我一直在尝试使用同步方法。问题是我根本看不到任何变化,它一直给我带来与使用它们之前相同的结果。我什至不知道我到底做错了什么,同步方法假设阻止其他同步方法在完成之前执行,对吗?希望你能给我一些关于正在发生的事情的线索。

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;
}
Run Code Online (Sandbox Code Playgroud)

nra*_*ner 5

同步只是确保方法不会同时执行。但是,它不保证任何执行顺序。

您需要确保print()在其他线程终止之前不会执行。这可以通过连接线程来实现。为此,执行

t.join();
t2.join();
Run Code Online (Sandbox Code Playgroud)

在启动打印线程之前或在执行其逻辑之前。

请注意,同步仍然是明智的,因为它确保增量和减量操作是原子地执行的。也就是说,count执行时的读取、递增和写入count++是同时执行的(另请参阅:为什么 i++ 不是原子的?)。从而防止以下执行顺序:

  • [线程“向上”]:加载count0
  • [线程“向下”]:加载count0
  • [线程“向上”]:递增count1
  • [线程“向下”]:递减count-1
  • [线程“上”]:存count1
  • [线程“下”]:存count-1

(这是数据库术语中的“丢失更新”。)