目录
一、简介
我们知道线程在工作的时候有自己的私有内存,工作内存。程序运行的时候从主内存拉取需要的变量到工作内存,处理完再返回主内存。这篇文章总结哪些代码会使线程去主内存拉取变量。
二、volatile
volatile修饰的变量,不论什么语句都会从主内存拉取变量。
public class Test01 {
public volatile boolean b = true;
public void m() {
System.out.println("start");
while(this.b){
}
System.out.println("end");
}
public static void main(String[] args) {
Test01 test = new Test01();
new Thread(new Runnable() {
@Override
public void run() {
test.m();
}
}).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("set");
test.b = false;
}
}
该程序能顺利完成,不会死循环。
三、synchronized
调用其他synchronized加锁的代码块,系统会从主内存拉取变量
public class Test01 {
public boolean b = true;
public Object lock = new Object();
public void m() {
System.out.println("start");
while(this.b){
synchronized(lock) {
}
}
System.out.println("end");
}
public static void main(String[] args) {
Test01 test = new Test01();
new Thread(new Runnable() {
@Override
public void run() {
test.m();
}
}).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("set");
test.b = false;
}
}
这种情况同样不会死循环。
注意,synchronized加锁后用到的变量才会从主内存拉取。
public class Test01 {
public boolean b = true;
public Object lock = new Object();
public void m() {
System.out.println("start");
synchronized(lock) {
while(this.b){
}
}
System.out.println("end");
}
public static void main(String[] args) {
Test01 test = new Test01();
new Thread(new Runnable() {
@Override
public void run() {
test.m();
}
}).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("set");
test.b = false;
}
}
这种情况,程序会死循环。
四、不会从主内存拉取的操作
只要不影响到变量的值,变量不参与运算,则不会从主内存中拉取,比如while,if,赋值给其他变量,作为方法参数等
public class Test01 {
public boolean b = true;
public Object lock = new Object();
public void m() {
System.out.println("start");
while(this.b){
doSomething();
if(b) {
}
boolean value = b;
}
System.out.println("end");
}
public void doSomething() {
}
public static void main(String[] args) {
Test01 test = new Test01();
new Thread(new Runnable() {
@Override
public void run() {
test.m();
}
}).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("set");
test.b = false;
}
}
这种情况,程序会死循环。
如果调用了被synchronized加锁的方法,或者方法中有被synchronized加锁的代码块,那么变量将会从主内存中拉取。
public class Test01 {
public boolean b = true;
public Object lock = new Object();
public void m() {
System.out.println("start");
while(this.b){
doSomething();
}
System.out.println("end");
}
public void doSomething() {
synchronized(lock) {
}
}
public static void main(String[] args) {
Test01 test = new Test01();
new Thread(new Runnable() {
@Override
public void run() {
test.m();
}
}).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("set");
test.b = false;
}
}
调用的synchronized加锁的方法即使锁的是毫不相干的对象,同样会使得变量从主内存拉取
public class Test01 {
public boolean b = true;
public Object lock = new Object();
public void m() {
System.out.println("start");
while(this.b){
System.out.println(this.b);
}
System.out.println("end");
}
public static void main(String[] args) {
Test01 test = new Test01();
new Thread(new Runnable() {
@Override
public void run() {
test.m();
}
}).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("set");
test.b = false;
}
}
这里的System.out.println锁的是PrintStream的实例,更是毫不相关
这种情况,程序不会死循环。
五、从主内存中拉取的操作
变量被赋值,变量参与计算,比如加减乘除,字符串拼接,++,--等操作,线程休眠会使从主内存中拉取变量。
public class Test01 {
public boolean b = true;
public Object lock = new Object();
public void m() {
System.out.println("start");
while(this.b){
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("end");
}
public static void main(String[] args) {
Test01 test = new Test01();
new Thread(new Runnable() {
@Override
public void run() {
test.m();
}
}).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("set");
test.b = false;
}
}
public class Test01 {
public boolean b = true;
public Object lock = new Object();
public void m() {
System.out.println("start");
while(this.b){
String str = b + "";
}
System.out.println("end");
}
public static void main(String[] args) {
Test01 test = new Test01();
new Thread(new Runnable() {
@Override
public void run() {
test.m();
}
}).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("set");
test.b = false;
}
}
这种情况,程序不会死循环