当我把一个新值赋给变量时,它在start()之后不会改变,但是在我使用join()之后它会改变。为什么会发生这种情况,在这种情况下int a是否应该是易变的?
class SampleThread extends Thread {
private static int a = 0;
@Override
public void run() {
a = 3;
}
public static void main(String[] args) throws InterruptedException {
Thread t2 = new Thread(new SampleThread());
t2.start();
System.out.println(a);
}
}
3条答案
按热度按时间3vpjnl9f1#
要了解正在发生的事情,请尝试以下方法:
仅限
run
方法已更改,其余代码未更改mcdcgff02#
如果您希望不同线程中的事情以特定的顺序发生——在本例中,是这样的
a = 2
在“system.out.println(a)”之前执行—然后必须编写代码以实现该顺序。在这种不重要的情况下,没有真正的工作在做,几乎任何你能做的事情都使得线程的使用毫无意义。主线程可以“连接”正在设置的线程
a
到2,但是您所获得的只是一种昂贵的方式来执行可以在单个线程中执行的代码。5anewei63#
是的,它需要挥发。
每根线都有一枚邪恶的硬币。线程在读取或写入字段时随时翻转硬币:heads,线程使用它自己的本地(到线程)副本;如果是写的,那么更新不会反映到所有其他线程,其他线程仍然会看到“old”值;如果是读的,那么同样的处理:读取它所拥有的任何内容,即使其他线程已经更新了它。即使他们一小时前就这么做了。它确实刷新了其他线程对此的视图,并且不会使用本地副本。
这枚硬币是邪恶的:它不是一枚公平的硬币。它将在今天的每一次,明天的每一次,测试套件期间的每一次,以及整个这一周为早期采用它的客户提供实时服务。然后当那个大客户进来你要演示的时候?它每次都会翻转来破坏你的应用程序。那种邪恶。
所以,你必须消除所有投币,或者至少确保投币的结果不会影响你的应用程序。
要做到这一点,首先要建立关系。在由vm执行的任何两行java代码之间,有一组规则来确定这两行是否有这样的关系:一行保证在另一行之后运行。这与它们是否运行无关(它们运行时的时间戳完全无关),而是java内存模型是否规定了这种关系的存在。
如果是的话,就没有硬币被翻转:“根据jmm,前面的线”所做的任何事情,对于后面的线来说都是明显可见的。但是如果jmm没有明确说明这种关系的存在,那么硬币就被抛了,你就输了。
单个线程中存在一个微不足道的“先到先得”关系:
x = 5; System.out.println(x);
琐碎地有这样的关系;他们走同一条线,一个接一个。那是免费的。但是在线之间,哦,亲爱的。你需要
synchronized
,volatile
,或者调用在内部执行这些操作的代码,或者调用具有其他机制来确保这些操作的代码(提示:java.util.concurrent包中有很多优秀的东西,顾名思义,它通常以非常有效的方式实现线程安全。例如,一个AtomicInteger
几乎总是比volatile int
,并且可以做更多的事情,比如cas操作,这是volatile int所不能做的。