Java多线程信息共享及volatile关键字

多线程信息共享

  • 线程类
    – 通过继承Thread或实现Runnable接口
    – 通过start方法,调用run方法,run方法工作
    – 线程run结束后,线程退出
  • 粗粒度:子线程与子线程之间、main线程之间缺乏交流
  • 细粒度:线程之间有信息交流通讯
    通过共享变量达到信息共享
    – JDK原生库暂不支持发送消息(类似MPI并行库直接发送消息)
    MPI是一个信息传递应用程序接口,包括协议和语义说明。MPI的目标是高性能,大规模性,和可移植性。MPI在今天仍为高性能计算的主要模型
  • 通过共享变量在多个线程中共享消息
    – static变量
    – 同一个Runnable类的成员变量
/**
 * @ClassName:ThreadDemo0
 * @Description:
 * @author: Torey
 */
public class ThreadDemo0 {
    public static void main(String[] args){
        for (int i = 0; i < 4; i++) {
            new TestThread0().start();
        }
    }
}
class TestThread0 extends Thread{
    //每个线程卖2张,4个线程卖8张
    private int tickets=2;
    //所有线程卖2张,4个线程卖2张
    //private static int tickets=2;
    @Override
    public void run() {
        while (true){
            if (tickets>0) {
                tickets--;
                System.out.println(Thread.currentThread().getName() + " tickets=" + tickets);
            }else {break;}
        }
    }
}
/**
 * @ClassName:ThreadDemo1
 * @Description:
 * @author: Torey
 */
public class ThreadDemo1 {
    public static void main(String[] args){
        TestDemo1 testDemo1=new TestDemo1();
        //两个线程共享一个对象
        new Thread(testDemo1).start();
        new Thread(testDemo1).start();
    }
}
class TestDemo1 implements Runnable{
    private volatile static int tickets=4;
    public void run() {
        while (true) {
            if (tickets>0) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                tickets--;
                System.out.println(Thread.currentThread().getName()
                        +" :"+tickets);
            }else {
                break;
            }
        }
    }
}

多线程共享问题

  • 多线程信息共享问题
    工作缓存副本
    关键步骤缺乏加锁限制
  • i++,并非原子性操作
    – 读取主存i(正本)到工作缓存(副本)中
    – 每个CPU执行(副本)i+1操作
    – CPU将结果写入到缓存(副本)中
    – 数据从工作缓存(副本)刷到主存(正本)中
    工作缓存发(副本):是每个线程独有的内存空间
  • 变量副本问题的解决方法
    – 采用volatile关键字修饰变量
    – 保证不同线程对共享变量操作时的可见性

volatile关键字代码示例

如下:不加volatile的变量,当主线程将flag设置为false后,子线程不能及时的读取到,导致while一直执行
在这里插入图片描述
加volatile的变量,当主线程将flag设置为false后,子线程可以及时的读取到,while循环跳出
在这里插入图片描述
源码如下:

/**
 * @ClassName:ThreadDemo2
 * @Description:volatile变量的使用
 * @author: Torey
 */
public class ThreadDemo2 {
    public static void main(String[] args) throws InterruptedException {
        TestThread2 t = new TestThread2();
        t.start();
        Thread.sleep(2000);
        t.flag=false;
        System.out.println("main thread is exiting");}}
class TestThread2 extends Thread{
  //  boolean flag=true;//子线程不会停止,while里用的是工作缓存中的flag值,值是true,而主存里flag值为false,主存里的不能及时刷新到工作缓存中
      volatile boolean flag=true;//用volatile修饰的变量可以及时在各线程里面通知
    @Override
    public void run() {
        int i=0;
        while (flag){i++;}
        System.out.println("test thread is exiting");
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章