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");
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章