多线程中的可见性问题

问题原因

现在有两个线程,在线程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只能保证可见性,不能保证原子性