多线程中的可见性问题
问题原因
现在有两个线程,在线程A中修改了线程B中的类属性,结果在线程B中根本没有接收到。代码如下所示:
package com.bobo;/**
* Created by wuxiaobo on 2018/10/28.
*/
/**
* @author [email protected]
* @create 2018-10-28 9:32
**/
public class Test {
public static void main(String[] args) {
Game game = new Game();
game.start();
try {
Thread.sleep(1000);
} catch (Exception e) {
}
game.index= -1;
System.out.println("change.....");
}
}
class Game extends Thread {
public int index = 0;
@Override
public void run() {
System.out.println("Game Start");
while (true) {
if (index == -1) {
break;
}
}
System.out.println("Game End");
}
}
结果,如下图所示:
其实在main线程中修改game属性的时候,在game线程中其实并不知道它的属性被修改了,所以导致一直停不下
来。网上百度来的图:
现在就是修改的副本,所以解决方式就是把那个变量发在主内存中。
解决方式
使用volatile关键字
class Game extends Thread {
public volatile int index = 0;
@Override
public void run() {
System.out.println("Game Start");
while (true) {
if (index == -1) {
break;
}
}
System.out.println("Game End");
}
}
volatile可以保证可见性,volatile只能保证可见性,不能保证原子性。
使用原子类
package com.bobo;/**
* Created by wuxiaobo on 2018/10/28.
*/
import java.util.concurrent.atomic.AtomicInteger;
/**
* @author [email protected]
* @create 2018-10-28 9:32
**/
public class Test {
public static void main(String[] args) {
Game game = new Game();
game.start();
try {
Thread.sleep(1000);
} catch (Exception e) {
}
game.index.set(-1);
System.out.println("change.....");
}
}
class Game extends Thread {
public AtomicInteger index;
public Game() {
index = new AtomicInteger(0);
}
@Override
public void run() {
System.out.println("Game Start");
while (true) {
if (index.get() == -1) {
break;
}
}
System.out.println("Game End");
}
}
原子类的一种实现方式是CAS,在底层中使用了volatile ,可以在AtomicInteger 看到这样的一个属性 private
volatile int value;
使用synchronized
package com.bobo;/**
* Created by wuxiaobo on 2018/10/28.
*/
/**
* @author [email protected]
* @create 2018-10-28 9:32
**/
public class Test {
public static void main(String[] args) {
Game game = new Game();
game.start();
try {
Thread.sleep(1000);
} catch (Exception e) {
}
game.setIndex(-1);
System.out.println("change......");
}
}
class Game extends Thread {
public int index = 0;
public synchronized int getIndex() {
return index;
}
public synchronized void setIndex(int index) {
this.index = index;
}
@Override
public void run() {
System.out.println("Game Start");
while (true) {
if ( this.getIndex()== -1) {
break;
}
}
System.out.println("Game End");
}
}
总结
synchronized和volatile的比较
1.volatile不需要加锁,比synchronized更轻量级,不会阻塞线程
2.从内存可见性角度讲,volatile读操作=进入synchronized代码块(加锁),volatile写操作=
退出synchronized代码块(解锁)
3.synchronized既能保证可见性,又能保证原子性,而volatile只能保证可见性,不能保证原子性