1. 程式人生 > 實用技巧 >Java多執行緒完結!!!

Java多執行緒完結!!!

執行緒狀態(20-12-09)

new -->就緒狀態 <-->執行狀態-->dead

阻塞狀態-->就緒狀態<-->執行狀態-->阻塞狀態

停止執行緒:

不推薦使用JDK提供的stop()、destroy()方法

推薦執行緒自己停止下來

建議使用一個標誌位進行終止變數,當flag=false,則終止執行緒執行

執行緒休眠

sleep(時間)指定當前執行緒阻塞的毫秒數

sleep存在異常InterruptedException

sleep時間達到後執行緒進入就緒狀態

sleep可以模擬網路延時,倒計時等

每一個物件都有一個鎖,sleep不會釋放鎖

執行緒禮讓

yield

禮讓執行緒,讓當前正在執行的執行緒暫停,但不阻塞

將執行緒從執行狀態轉為就緒狀態

讓CPU重新排程,禮讓不一定成功!看CPU心情

執行緒強行執行 join

join合併執行緒,待此執行緒執行完成後,再執行其他執行緒,其他執行緒阻塞

可以想象成插隊

執行緒狀態觀測 state

Thread.State;//五大狀態

執行緒優先順序 priority

優先順序低只是意味著獲得排程的概率低,並不是優先順序低就不會被排程了。這都是看CPU的排程

守護執行緒 daemon

執行緒分為使用者和守護執行緒

虛擬機器必須保護使用者執行緒執行完畢

虛擬機器不必等待守護執行緒執行完畢

如,後臺記錄操作日誌,監控記憶體,垃圾等待回收等待

執行緒同步(20-12-09)

執行緒安全 synchronized

執行緒同步:多個執行緒操作同一個資源

例.執行緒不安全的集合

public static void main(String[] args) {
        List<String> list=new ArrayList<String>();
        for(int i=0 ; i<10000;i++){
            new Thread(()->{
                list.add(Thread.currentThread().getName());
            }).start();
        }
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(list.size());
    }

同步方法:synchronized 方法 和 synchronized 塊

前者直接在方法上加就可以;後者要把方法體包在synchronized 塊中

鎖的物件就是變化的量,需要增刪改的物件!!!

或使用本身就是安全的類 CopyOnWriteArrayList

public static void main(String[] args) {
        CopyOnWriteArrayList<String> list=new CopyOnWriteArrayList<String>();
        //CopyOnWriteArrayList本身就是執行緒安全的
        for (int i = 0; i < 10000; i++) {
            new Thread(()->{
                list.add(Thread.currentThread().getName());
            }).start();
        }
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(list.size());
    }

死鎖(20-12-09)

死鎖:多個執行緒互相抱著對方需要的資源,然後形成僵持

死鎖第四個必要條件:

1.互斥條件:一個資源每次只能被一個程序使用。
2.請求與保持條件: 一個程序因請求資源而阻塞時,對已獲得的資源保持不放。
3.不剝奪條件 :程序已獲得的資源,在未使用完之前,不能強行剝奪。
4.迴圈等待條件:若干程序之間形成一種頭尾相接的迴圈等待資源關係。

Lock(鎖)

例項

public class TestLock {
    public static void main(String[] args) {
        TestLock2 testLock2 = new TestLock2();

        new Thread(testLock2).start();
        new Thread(testLock2).start();
        new Thread(testLock2).start();
    }
}

class TestLock2 implements Runnable{

    int ticketNums=10;

    //定義lock鎖
    private final ReentrantLock lock=new ReentrantLock();

    @Override
    public void run() {
        while (true){
           try {//加鎖要使用try finally
            lock.lock();//加鎖
            if(ticketNums>0){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(ticketNums--);
            }else {
                break;
            }
        }
        finally{
            lock.unlock();
           }
        }
    }
}

synchronized 與 Lock 的對比

Lock是顯式鎖(手動開啟和關閉鎖,別忘記關閉鎖) synchronized是隱式鎖, 出了
作用域自動釋放
Lock只有程式碼塊鎖,syrichronized有程式碼塊鎖和方法鎖
使用Lock鎖,JVM將花費較少的時間來排程執行緒,效能更好。並且具有更好的擴充套件
性(提供更多的子類)
優先使用順序:
Lock >同步程式碼塊(已經進入了方法體,分配了相應資源) >同步方法(在方法體之外)

執行緒通訊(20-12-09)

生產者/消費者問題

管程法

生產者將生產好的資料放入緩衝區,消費者從緩衝區拿出資料

...

訊號燈法

設定一個標誌位

public class TestPC2 {
    public static void main(String[] args) {
        TV tv = new TV();
        new Player(tv).start();
        new Watcher(tv).start();
    }
}

class Player extends Thread{
    TV tv;
    public Player(TV tv){
        this.tv=tv;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            if(i%2==0){
                this.tv.play("快樂大本營");
            }else{
                this.tv.play("抖音");
            }
        }
    }
}

class Watcher extends Thread{
    TV tv;

    public Watcher(TV tv) {
        this.tv = tv;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            tv.watch();
        }
    }
}

class TV{

    String voice;
    boolean flag=true;

    public synchronized void play(String voice) {
        if (!flag) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("演員表演了:" + voice);

            this.notifyAll();//喚醒
            this.voice = voice;
            this.flag = !this.flag;
        }
    }


    public synchronized void watch(){
        if(flag){
            try {
                this.wait();//等待
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("觀看了:"+voice);

        this.notifyAll();//喚醒
        this.flag=!this.flag;
    }

}

執行緒池(20-12-09)

ExecutorService:真正的執行緒池介面。常見子類 ThreadPoolExecutor

Executors:工具類、執行緒池的工廠類,用於建立並返回不同型別的執行緒池

總結

三種執行緒建立

//回顧執行緒建立
public class ThreadNew {
    public static void main(String[] args) {
        new MyThread1().start();

        new Thread(new MyThread2()).start();

        FutureTask<Integer> futureTask=new FutureTask<Integer>(new MyThread3());
        new Thread(futureTask).start();

        try {
            Integer integer=futureTask.get();
            System.out.println(integer);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }

}

//1.繼承Thread類
class MyThread1 extends Thread{
    @Override
    public void run() {
        System.out.println("MyThread1");
    }
}

//2.實現Runnable介面
class MyThread2 implements Runnable{
    @Override
    public void run() {
        System.out.println("MyThread2");
    }
}

//3.實現Callable介面
class MyThread3 implements Callable<Integer>{
    @Override
    public Integer call() throws Exception {
        System.out.println("MyThread3");
        return 100;
    }
}