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

huangapple go评论82阅读模式
英文:

Why do these synchronized methods keep giving me different outputs?

问题

我需要这些线程对相同的数据具有访问权限,以便在不相互干扰的情况下同时执行,因此我尝试使用同步方法代替 Thread.join()。问题是我根本看不到任何变化,它仍然给我之前使用它们时的相同结果。我甚至不知道我到底做错了什么,同步方法应该防止其他同步方法在它们完成之前执行,对吧?希望您能给我一些关于发生了什么的线索。

public class ThreadSync{
    public static void main(String[] args) throws InterruptedException {
         //如果正确执行	
	     //输出除了 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;
}
英文:

I need this threads that have access to the same data to be execute simultaneously without messing around with each other, so instead using Thread.join() I've been trying with synchronized methods. Problem is that I see no change at all, it keep giving me the same result that I had before using them. I don't even know what exactly I'm doing wrong, synchronized
methods suppose to prevent other synchronized methods to execute until they are done, right? Hope you can give me some clue about what is goin' on.

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;
}

答案1

得分: 5

同步仅确保这些方法不会同时执行,但不保证任何执行顺序。

您需要确保在其他线程终止之前不会执行 print()。可以通过加入这些线程来实现。要这样做,请在启动打印线程之前或在执行其逻辑之前执行以下操作:

t.join();
t2.join();

请注意,同步仍然是明智的,因为它确保原子地执行增减操作。也就是说,在执行 count++ 时,同时执行读取、增加和写入 count(参见:https://stackoverflow.com/questions/25168062/why-is-i-not-atomic)。从而防止以下执行顺序:

  • [线程“up”]:将 count 加载为值 0
  • [线程“down”]:将 count 加载为值 0
  • [线程“up”]:将 count 增加到 1
  • [线程“down”]:将 count 减少到 -1
  • [线程“up”]:将值 1 存储到 count
  • [线程“down”]:将值 -1 存储到 count

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

英文:

The synchronization just ensures that the methods are not executed at the same time. However, it does not guarantee any execution order.

You need to ensure that print() is not executed before the other threads have terminated. This could be achieved by joining the threads. To do so, execute

t.join();
t2.join();

either before starting the print thread or before executing its logic.

Note that the synchronization is still sensible because it ensures that the increment and decrement operations are executed atomically. That is, that reading, incrementing, and writing count when executing count++ are executed at once
(see also: https://stackoverflow.com/questions/25168062/why-is-i-not-atomic). Thereby it prevents the following execution sequence:

  • [Thread "up"]: load count with value 0
  • [Thread "down"]: load count with value 0
  • [Thread "up"]: increment count to 1
  • [Thread "down"]: decrement count to -1
  • [Thread "up"]: store count with value 1
  • [Thread "down"]: store count with value -1

(This is a "lost update" in database terms.)

答案2

得分: 2

synchronized 防止你的线程同时访问该字段,但当然它并不保证线程执行的顺序。例如,如果纯粹偶然情况下,“上”线程先执行,然后“打印”线程第二次执行,最后“下”线程执行,输出将为1,即使在所有线程完成后计数器的值为0。

英文:

synchronized prevens your thread from accessing the field simultaneously, but of course it provides no guarantee regarding the order in which the threads execute.
For example, if, by pure chance, the "Up" thread executes first, the "Print" thread second and the "Down" thread last, the output will be 1, even though the counter value is 0 after all threads are finished.

huangapple
  • 本文由 发表于 2020年8月21日 15:12:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/63518147.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定