可见性
在多个线程之间,一个线程操作共享变量发生改变,它的值会立刻被更改到主存当中,其他线程去操作共享变量时获取到的是内存中的新值。
Volatile
volatile是作用在一个变量上,它保证了不同线程对这个变量的操作可见性
valatitle禁止指令重排序;java代码书写的顺序与实际执行的顺序不同,指令重排序一种对处理器提高程序性的优化
例如:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33public class RunThread extends Thread {
private boolean isRunning=true;
public boolean isRunning() {
return isRunning;
}
public void setRunning(boolean running) {
isRunning = running;
}
public void run() {
System.out.println("进入run...");
while (isRunning==true){
}
System.out.println("线程被停止了");
}
}
public class Test {
public static void main(String[] args) throws InterruptedException {
RunThread runThread=new RunThread();
runThread.start();
Thread.sleep(1000);
runThread.setRunning(false);
System.out.println("已经赋值false");
}
}
结果:(进入死锁状态)1
2进入run...
已经赋值false
这个问题就是私有堆栈中的值和公有堆栈中的值不同步造成的,关键字volatile的作用会强制从公共堆栈中取得变量。解决办法就是在isRunning加上volatile关键字
改进1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22public class RunThread extends Thread {
private volatile boolean isRunning=true;
public boolean isRunning() {
return isRunning;
}
public void setRunning(boolean running) {
isRunning = running;
}
public void run() {
System.out.println("进入run...");
while (isRunning==true){
}
System.out.println("线程被停止了");
}
}
结果:1
2
3
4
5进入run...
已经赋值false
线程被停止了
Process finished with exit code 0
Volatile与sychronized比较
- Volatile是线程轻量级的实现,Volatile只修饰变量,sychronized可作用于方法和代码块。
- 多线程访问Volatile不会发生阻塞,而sychronized会出现阻塞。
- Volatile可以保证数据可见性,但不能保证原子性,sychronized可以保证原子性。
- Volatile是解决变量在多线程之间的可见性,sychronized关键字解决的是多个线程之间访问资源的同步性。
Synchronized 它包含互斥性和可见性
同步sychronized可以解决一个线程看到对象对于不一致的状态,还可以保证进入同步方法或者同步代码块的每个线程,都看到由同一个锁保护之前所有的修改效果。
例如:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53public class Service {
private boolean isContinueRun = true;
public void RunMethod(){
while (isContinueRun == true){
}
System.out.println("停下来!");
}
public void StopMethod(){
isContinueRun=false;
}
}
public class ThreadC extends Thread {
private Service service;
public ThreadC(Service service) {
this.service = service;
}
public void run() {
service.RunMethod();
}
}
public class ThreadD extends Thread {
private Service service;
public ThreadD(Service service) {
this.service = service;
}
public void run() {
service.StopMethod();
}
}
public class Run {
public static void main(String[] args) throws InterruptedException {
Service service=new Service();
ThreadC threadC=new ThreadC(service);
threadC.start();
Thread.sleep(1000);
ThreadD threadD=new ThreadD(service);
threadD.start();
System.out.println("已经发起停止命令!");
}
}
结果:1
已经发起停止命令!
由结果可见,出现死循环,造成的原因是各线程间的数据没有可视性造成的,而Synchronized可以具有可视性
改进:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17public class Service {
private boolean isContinueRun = true;
public void RunMethod(){
String str=new String();
while (isContinueRun == true){
synchronized (str){
}
}
System.out.println("停下来!");
}
public void StopMethod(){
isContinueRun=false;
}
}
结果:1
2
3
4已经发起停止命令!
停下来!
Process finished with exit code 0