kat*_*ex7 2 java concurrency multithreading visibility happens-before
现在 stackoverflow 上已经有很好的答案,但他们没有给我想要的明确答案。
\n\n说你有方法
\n\nDosomething();\n doAnother();\n int x = 5;\n Runnable r = new Runnable(){\n public void run(){\n int y = x;\n x = 7;\n System.out.println(z);}\n }\n new Thread(r).start()\nRun Code Online (Sandbox Code Playgroud)\n\n现在,同时该方法正在运行,并且在调用 thread.start 之前,一些全局非易失性变量 z 从 4 更改为 5。
\n\n由于 z 发生在 thread.start 之前,程序是否能保证打印 5?
\n\n另外,如果我们以某种方式谈论它,那么可以肯定地说 thread.start() 永远不能重新排序。
\n\n就被称为启动的线程而言,这意味着,就好像到该点为止的所有内容都是顺序的。例如说我们有
\n\nint k = 8;\nnew Thread(() -> {}).start()\nRun Code Online (Sandbox Code Playgroud)\n\n现在...从该线程的角度来看,无论首先调用 start 还是 k 被分配 8,都不会产生任何影响。因此可以重新排序,但由于发生在保证之前,这不可能吗?
\n\njava 规范并没有给出强有力的声明来说明这一点。相反它说
\n\n当语句调用\xc2\xa0Thread.start()时,与该语句有happens-before关系的每个语句
\n\n然而 k = 8 并不表示 a 发生在与该语句的关系之前......
\n\n我什至不确定他们的意思是什么,除非您使用相同的监视器锁定,否则在与启动方法的关系之前发生了一些事情
\n\nsynchronized(this){ int k = 8;}\n synchronized(this) { new Thread(() -> {}).start();}\nRun Code Online (Sandbox Code Playgroud)\n\n对于更可怕的情况,我们有这段代码
\n\nSocket con = socket.accept();\nRunnable r = new Runnable(){ \n public void run(){\n handleRequest(con)}\n }\nnew Thread(r).start();\nRun Code Online (Sandbox Code Playgroud)\n\n然后新线程碰巧发现 con 为 null?
\n\n有人能给我关于这些主题的明确答案吗?
\n由于 z 发生在 thread.start 之前,程序是否能保证打印 5?
如果 z 的值是由调用 start() 方法的线程设置的,那么是的。否则,不行。新启动的线程保证能看到启动它的线程所做的更改,而不是其他线程所做的更改。
另外,如果我们以某种方式谈论它,那么可以肯定地说 thread.start() 永远不能重新排序。
要点是 - 新启动的线程保证看到 k 的值为 8。如果新启动的线程不读取 k (或父线程设置的任何其他变量),则允许编译器重新排序此类操作,但这对程序员来说并不重要(无论如何程序员都会得到保证)
然后新线程碰巧发现 con 为 null?
假设新线程拥有对 con 的引用,则保证 con 在新线程启动之前被初始化(因为 JMM 保证在调用 start() 之前父线程所做的任何更改对于新线程都是可见的)
总结一下 - 一个线程 (T1) 启动另一个线程 (T2),那么 T1 在启动 T2 之前所做的任何更改都保证对 T2 可见。作为一名程序员,这才是最重要的。只要不违反此保证,编译器就可以执行重新排序。您当然可以参考 JLS,但我认为您已经参考过。