Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/343.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 这是否需要同步块?_Java_Multithreading - Fatal编程技术网

Java 这是否需要同步块?

Java 这是否需要同步块?,java,multithreading,Java,Multithreading,是System.out.println(编号)上的同步块需要以下代码吗 import java.util.concurrent.CountDownLatch; public class Main { private static final Object LOCK = new Object(); private static long number = 0L; public static void main(String[] args) throws Interr

System.out.println(编号)上的同步块需要以下代码吗

import java.util.concurrent.CountDownLatch;

public class Main {

    private static final Object LOCK = new Object();

    private static long number = 0L;

    public static void main(String[] args) throws InterruptedException {

        CountDownLatch doneSignal = new CountDownLatch(10);

        for (int i = 0; i < 10; i++) {
            Worker worker = new Worker(doneSignal);
            worker.start();
        }

        doneSignal.await();

        synchronized (LOCK) { // Is this synchronized block need?
            System.out.println(number);
        }
    }

    private static class Worker extends Thread {

        private final CountDownLatch doneSignal;

        private Worker(CountDownLatch doneSignal) {
            this.doneSignal = doneSignal;
        }

        @Override
        public void run() {
            synchronized (LOCK) {
                number += 1;
            }
            doneSignal.countDown();
        }

    }
}
import java.util.concurrent.CountDownLatch;
公共班机{
私有静态最终对象锁=新对象();
专用静态长编号=0L;
公共静态void main(字符串[]args)引发InterruptedException{
CountDownLatch doneSignal=新的CountDownLatch(10);
对于(int i=0;i<10;i++){
工人=新工人(doneSignal);
worker.start();
}
doneSignal.wait();
已同步(锁定){//是否需要此同步块?
系统输出打印项次(编号);
}
}
私有静态类工作线程扩展{
私人最终倒计时信号;
私人工人(倒计时信号){
this.doneSignal=doneSignal;
}
@凌驾
公开募捐{
已同步(锁定){
数字+=1;
}
doneSignal.countDown();
}
}
}
我认为这是必要的,因为有可能读取缓存的值

但有人说:

这是不必要的。
因为当主线程读取变量
number
时,所有工作线程都在变量
number
的内存中执行了写操作
doneSignal.wait()
是一个阻塞调用,所以只有当所有
worker
线程都调用了
doneSignal.countDown()时,
main()
才会继续
,使其达到0,这就是
await()方法返回的原因

System.out.println()
之前添加
synchronized
块没有意义,此时所有线程都已完成

考虑使用
AtomicInteger
作为
number
而不是针对锁进行同步以调用
+=1

无需:

CountDownLatch doneSignal = new CountDownLatch(10);

for (int i = 0; i < 10; i++) {
  Worker worker = new Worker(doneSignal);
  worker.start();
}
doneSignal.await();
// here the only thread running is the main thread

只有当10个线程完成它们的工作时,doneSignal.await()才有效;行将被超越。

这是不必要的,因为您正在等待“完成”信号。以一种方式刷新内存,使等待线程中的所有值对主线程可见


但是,您可以很容易地进行测试,在
run
方法中进行一个需要几个(数百万)步骤的计算,并且不会被编译器优化,如果您看到的值与预期的最终值不同,那么您的最终值对于主线程来说是不可见的。当然,这里的关键部分是确保计算不会得到优化,因此一个简单的“增量”可能会得到优化。一般来说,当您不确定是否有正确的内存障碍时,这对测试并发性是有用的,因此以后可能会对您有用。

需要时

没有

但是,由于没有(记录在案的)保证不会有任何交错,因此可以找到交错的日志条目

System.out.println("ABC");
System.out.println("123");
可以打印:

AB1
23C
值得

几乎可以肯定不是。大多数JVM将使用锁实现
println

边缘大小写

正如@DimitarDimitrov所建议的,该锁还有一个可能的用途,那就是确保在访问
数字之前跨越内存障碍。如果这是一个问题,那么您不需要
锁定
,只需将
编号
设置为易失性

private static volatile long number = 0L;

System.out.println(编号)周围不需要
synchronized
,但这不是因为
PrintWriter.println()
实现在内部同步,也不是因为在
doneSignal.await()时取消阻止所有工作线程的工作


synchronized
是不需要的,因为在每次调用
doneSignal.countDown
和完成
doneSignal.await()
之前,都有一个before边。这保证了您将成功地看到
number

的正确值。不管线程是否完成,重要的是读者是否可以看到实际的数值。幸运的是,pair countdown()+await()保证发生在:)之前。对于
doneSignal.await()
来说,重要的是
CountDownLatch
达到了0,而
number
发生了什么根本不重要。如果他同时删除了
CountDownLatch
,那么根据调度程序的不同,主线程可能会在所有
Worker
线程完成之前完成,并打印
0
或其他一些数字。我认为qwwdfsad的要点是,如果在每次
倒计时()之前的代码之间没有发生
await()
之后的代码,您仍然可以看到
number
的值小于10。例如,如果
await()
通过检查一个用旧的(Java 5.0之前的)
volatile
语义更新的值来工作,它可以可靠地看到所有线程都已完成,但无法可靠地看到
number
的最后一个值。谢谢@DimitarDimitrov,我现在得到了qwwdfsad所指的内容。然而,这些线程确实调用了
倒计时()
,因此“完成”包括信号传递,这就是保证在@micheleb出现问题之前不会发生的事情——没有人认为之前不会发生任何事情。我(并且我假设@qwwdsad)所争论的是,在打印结果时,before edge是不需要同步的主要原因,而不是所有线程都已完成的事实。OP关心的是查看
number
的正确更新值。通过同步
println()
实现无法解决此问题(除非对
编号
的更新是在同一监视器中完成的,很可能是
System.out
)。关于
volatile
u
private static volatile long number = 0L;