1>
什么是单个线程中语句的重新排序 。Ans。 编译器/ JVM对特定线程中的语句进行重新排序,以免影响单线程执行的代码语义。 例如,请参见以下代码。
class A{
private int k = 0;
private boolean l = false;
public void example(int a, boolean b){
k = a;//.... Line 1
l = b;//.... Line 2
}
public void show(){
System.out.println(k);//.... Line 3
System.out.println(l);//.... Line 4
}
public static void main(String args[]){
A a = new A();
a.example(3,"true");
a.show();
}
}
方案1 :在这里,第1行和第2行的执行顺序并不重要。
因为他们彼此不依赖。
因此,它们可能会重新排序。
现在很正常的是,在主线程中,行的执行顺序为2、1、3、4。
所以输出将是
3
真正
但是方法show()中的执行顺序永远无法重新排序。 因为那样会改变方法的语义。 那么结果如下
真正
3
但这不是该程序的目的。 因此,这永远不会发生。
方案2 :但是,当两个线程一起工作时,方案可能会有所不同。 假设在主线程中启动了两个线程。 线程1执行方法a.example(..),线程2执行a.show()此处的执行很可能按以下顺序进行。
2,3,4,1
现在输出如下
0
真正
这意味着k在l之前分配。
所以这不是我们想要的对吗?
2>
如何停止重新订购 ?Ans。 如果将变量k和l声明为volatile,则可以停止重新排序。
让我再次重写代码
class A{
private volatile int k = 0;
private volatile boolean l = false;
public boolean getL(){
return l;
}
public void example(int a, boolean b){
k = a;//.... Line 1
l = b;//.... Line 2
}
public void show(){
System.out.println(k);//.... Line 3
System.out.println(l);//.... Line 4
}
public static void main(String args[]){
A a = new A();
//code is omitted.
/*a.example(3,true) is run in thread1*/
/*a.show() is run in thread2*/
}
}
考虑场景2。在此重复:线程1执行a.example(),线程2执行a.show()。
现在一种可能的订购如下
1,3,4,2
然后输出如下
3
假
此处1在2之前执行。重新排序已停止。 因为如果变量是易失性的,则它们的访问顺序与编写代码的顺序相同。
但是我们想要这个吗? 我们需要查看分配的值3和“真”。
3>
怎么做呢?在线程2的run方法中,我们可以添加此代码
if(a.getL()){
a.show();
}
这两个线程执行的行将按照以下顺序
1,2,3,4
同样的输出如下
3
真正
4>
现在是一个棘手的问题 。假设我们有3个变量j,k和l。 我以以下形式写课
class A{
private volatile int j = 0;
private volatile int k = 0;
private volatile boolean l = false;
public void example(int a, boolean b){
j = a;//.... Line 1
k = a;//.... Line 2
l = b;//.... Line 3
}
public boolean getL(){
return l;
}
public void show(){
System.out.println(j)//... Line 4
System.out.println(k);//.... Line 5
System.out.println(l);//.... Line 6
}
public static void main(String args[]){
A a = new A();
//code is omitted.
/*a.example(3,true) is run in thread1*/
/*a.show() is run in thread2*/
}
}
因此,如果在线程2的run()方法中,我们将其写为前面的场景
if(a.getL()){
a.show();
}
结果将被排序。
执行顺序为
1,2,3,4,5,6和输出将是
3
3
真正
这是问题。 对于相同的输出,执行顺序可以如下吗?
2,1,3,4,5,6
答案是“是”。 因此,必须在l之前分配j和k。 但是没有必要在k之前分配j。
因此,j和k可能是非易失性的。 仅l需要是易失的。
5>
什么是挥发物 ?回答:
1>将易失性变量写入内存(为其分配了一些值)时,请确保在此易失性变量的写操作之前,必须在同一线程中的代码中进行所有先前的赋值/内存写操作。
2>每当读取volatile变量时,都必须从内存中读取它。 这就是为什么它可能会看到该值的原因,该值是在此读取之前编写的。
3>每当写入它们时,它们就会写入内存,而不是线程的本地缓存。
关于volatile还有其他一些事情。 我将在下一篇文章中提出。
From: https://bytes.com/topic/java/insights/951590-java-thread-essentials
本文深入探讨Java中线程间变量访问的重新排序问题,解释了volatile关键字如何确保变量的可见性和有序性,以及其在多线程环境中防止数据竞争的关键作用。
643

被折叠的 条评论
为什么被折叠?



