Java 使用“同步”获取意外值
我有一个简单的代码片段,并尝试对其进行一些实验,但在接下来的代码中,我不清楚输出数据的顺序:Java 使用“同步”获取意外值,java,multithreading,synchronized,Java,Multithreading,Synchronized,我有一个简单的代码片段,并尝试对其进行一些实验,但在接下来的代码中,我不清楚输出数据的顺序: public class Main { static int n = 100; public static synchronized int decreaseValue(){ return --n; } public static void main(String[] args) throws InterruptedException, IOExce
public class Main {
static int n = 100;
public static synchronized int decreaseValue(){
return --n;
}
public static void main(String[] args) throws InterruptedException, IOException {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
while(true){
try {
System.out.println("Thread1: "+ decreaseValue());
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
},"Thread1");
t1.start();
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
while(true){
try {
System.out.println("Thread2: "+ decreaseValue());
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
},"Thread2");
t2.start();
while(true){
try {
System.out.println("Main Thread: "+ decreaseValue());
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
无法理解,为什么我会在下一个顺序中获得这样的值:
线程1:89
螺纹2:90
主线:88
请注意N值,而不是调用线程的顺序:
Thread1: 99
Thread2: 98
Main Thread: 97
Main Thread: 95
Thread2: 94
Thread1: 96
Main Thread: 92
线程是并发运行的,没有任何东西会影响它们调用
decreaseValue()
函数的顺序。您希望它们是有序的,因为您正在执行相同数量的睡眠:),但一旦线程从睡眠开始/恢复,CPU就会将线程放入运行队列(创建执行顺序,这是同步将保证的顺序),因此,打印顺序取决于CPU如何将线程放入运行队列
如果您询问打印顺序,控制台上的打印也会同步(但不会与decreaseValue位于同一块中)。相同的逻辑适用于打印,就像减少值的逻辑一样
如果希望以与值递减相同的顺序查看打印,可以在
decreaseValue()
函数中移动打印。但这不会影响值递减的顺序 线程并行运行。你无法预测他们的执行顺序。您可以设置线程优先级,以确定其执行顺序的优先级 您一定在什么地方读到过,必须使用synchronized
来确保正确的订购,或者类似的东西。“排序”一词属于一个不同于您心目中的概念:它意味着对同步块的执行总是有一些明确的排序。订单事先不知道,但每次都会有。如果没有同步,您甚至无法得到保证:一个线程可以感知一个顺序,另一个线程可以感知另一个顺序,或者根本无法感知其他线程的任何操作
关于您的编辑:
如果您担心打印输出出现错误,这是因为您的
println
语句在synchronized
之外,因此可以独立于对decreaseValue
的调用进行交错,但是我使用synchronized block并获得下一个顺序的输出值:89,90,88-所以看起来synchronized block不起作用。synchronized
只确保一次只有一个线程可以执行该方法,它不保证任何顺序。但是在这种情况下,一个线程读取decrease方法中的n值时,另一种方法也可以访问它。@barn.gumbl你能提供更多的细节吗,为什么“看起来”?@barn.gumbl前三种方法是因为它们在队列中按顺序结束,然后CPU应用我的答案中给出的逻辑。看看我的最新答案你会期待什么?没有任何东西可以保证这些不同线程执行DecreatedValue()
的顺序。没有任何东西可以保证哪个线程将调用Decreatease方法,但据我所知,synchronized块应该保证输出值的有效顺序。在这种情况下,同步DecreatedValue()毫无意义,因为基类型(除了long和double)上的算术运算保证是原子的。我没有注意到System.out.println不是一个同步的方法。@ignis递减整数不是原子的,赋值给整数是。没有什么可以保证哪个线程会调用Decreatease方法,但据我所知,同步块应保证输出值的有效顺序。在这个方法中,一个线程似乎也可以访问另一个线程。