多線程進階——JUC併發編程以前夜

一、什麼是JUC

學習能夠參考:源碼+官方文檔 進行學習java

文檔地址:https://docs.oracle.com/javase/8/docs/api/面試

首先咱們看看什麼是JUC算法

其次咱們看看JUC都有哪些東西編程

因而咱們能夠總結下JUC能夠分爲五大類api

一、同步工具類多線程

二、lock類併發

三、原子類oracle

四、集合相關類框架

五、Executor框架相關類ide

二、JUC入門前言——嘮嗑 線程和進程

線程、進程,若是不能使用一句話說出來,說明技術不紮實!

進程:一個程序,QQ.exe  Music.exe  程序的集合;
一個進程每每能夠包含多個線程,至少包含一個!
Java默認有幾個線程? 2 個   mian、GC
線程:開了一個進程 Typora,寫字,自動保存(線程負責的) 對於Java而言:Thread、Runnable、Callable

Java 真的能夠開啓線程嗎? 開不了,咱們看看源碼

public synchronized void start() {
        /**
         * This method is not invoked for the main method thread or "system"
         * group threads created/set up by the VM. Any new functionality added
         * to this method in the future may have to also be added to the VM.
         *
         * A zero status value corresponds to state "NEW".
         */
        if (threadStatus != 0)
            throw new IllegalThreadStateException();

        /* Notify the group that this thread is about to be started
         * so that it can be added to the group's list of threads
         * and the group's unstarted count can be decremented. */
        group.add(this);

        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
                /* do nothing. If start0 threw a Throwable then
                  it will be passed up the call stack */
            }
        }
    }
    //本地方法,底層C++,java 無是沒法直接操做硬件的
    private native void start0();

併發、並行

併發編程:併發、並行
併發(多線程操做同一個資源)
    CPU 一核 ,模擬出來多條線程,天下武功,惟快不破,快速交替
並行(多我的一塊兒行走)
    CPU 多核 ,多個線程能夠同時執行; 線程池

public class Test1 {
    public static void main(String[] args) {
        // 獲取cpu的核數
        // CPU 密集型,IO密集型
        System.out.println(Runtime.getRuntime().availableProcessors());
    }
}

併發編程的本質:充分利用CPU的資源 
全部的公司都很看重!
企業,掙錢=> 提升效率,裁人,找一個厲害的人頂替三個不怎麼樣的人;
人員(減) 、技術成本(高) 

線程有幾個狀態

public enum State {
        //新建
        NEW,

        /運行
        RUNNABLE,

        //阻塞
        BLOCKED,

        //等待
        WAITING,
       
        //超時等待
        TIMED_WAITING,

        //終止
        TERMINATED;
    }

wait/sleep區別

一、來自不一樣的類 wait => Object
sleep => Thread

二、關於鎖的釋放 wait 會釋放鎖,sleep 睡覺了,抱着鎖睡覺,不會釋放!
三、使用的範圍是不一樣: wait必須在同步代碼塊中,sleep能夠在任何地方睡

三、Lock鎖(重點)

傳統Synchronized

/**
 * 真正的多線程開發,公司中的開發,下降耦合性
 * 線程就是一個單獨的資源類,沒有任何附屬的操做!
 * 一、 屬性、方法
 */
public class SaleTicketDemo01 {
    public static void main(String[] args) {
        // 併發:多線程操做同一個資源類, 把資源類丟入線程
        Ticket ticket = new Ticket();
        // @FunctionalInterface 函數式接口,jdk1.8  lambda表達式 (參數)->{ 代碼 }
        new Thread(()->{
            for (int i = 1; i < 40 ; i++) {
                ticket.sale();
            }
        },"A").start();

        new Thread(()->{
            for (int i = 1; i < 40 ; i++) {
                ticket.sale();
            }
        },"B").start();

        new Thread(()->{
            for (int i = 1; i < 40 ; i++) {
                ticket.sale();
            }
        },"C").start();
    }
}

// 資源類 OOP
class Ticket {
    // 屬性、方法
    private int number = 30;
    // 賣票的方式
    // synchronized 本質: 隊列,鎖
    public synchronized void sale(){
        if (number>0){
            System.out.println(Thread.currentThread().getName()+"賣出了"+(number--)+"票,剩餘:"+number);
        }
    }
}

Lock接口

實現類:可重入鎖、讀鎖、寫鎖

public ReentrantLock() {
        sync = new NonfairSync();//非公平鎖(默認)
    }

    /**
     * Creates an instance of {@code ReentrantLock} with the
     * given fairness policy.
     *
     * @param fair {@code true} if this lock should use a fair ordering policy
     */
    public ReentrantLock(boolean fair) {//公平鎖
        sync = fair ? new FairSync() : new NonfairSync();
    }

公平鎖:十分公平:能夠先來後到

非公平鎖:十分不公平:能夠插隊 (默認)
案例代碼:

public class SaleTicketDemo02  {
    public static void main(String[] args) {
        // 併發:多線程操做同一個資源類, 把資源類丟入線程
        Ticket2 ticket = new Ticket2();
        // @FunctionalInterface 函數式接口,jdk1.8  lambda表達式 (參數)->{ 代碼 }
        new Thread(()->{for (int i = 1; i < 40 ; i++) ticket.sale();},"A").start();
        new Thread(()->{for (int i = 1; i < 40 ; i++) ticket.sale();},"B").start();
        new Thread(()->{for (int i = 1; i < 40 ; i++) ticket.sale();},"C").start();
    }
}
// Lock三部曲
// 一、 new ReentrantLock();
// 二、 lock.lock(); // 加鎖
// 三、 finally=>  lock.unlock(); // 解鎖
class Ticket2 {
    // 屬性、方法
    private int number = 30;

    Lock lock = new ReentrantLock();

    public void sale(){
        lock.lock(); // 加鎖
        try {
            // 業務代碼
            if (number>0){
                System.out.println(Thread.currentThread().getName()+"賣出了"+(number--)+"票,剩餘:"+number);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock(); // 解鎖
        }
    }
}

Synchronized 和 Lock 區別

一、Synchronized   內置的Java關鍵字,  Lock 是一個Java類

二、Synchronized  沒法判斷獲取鎖的狀態,Lock  能夠判斷是否獲取到了鎖
三、Synchronized  會自動釋放鎖,lock 必需要手動釋放鎖!若是不釋放鎖,死鎖

四、Synchronized   線程 1(得到鎖,阻塞)、線程2(等待,傻傻的等);Lock鎖就不必定會等待下 去;
五、Synchronized    可重入鎖,不能夠中斷的,非公平;Lock ,可重入鎖,能夠 判斷鎖,非公平(能夠 本身設置);
六、Synchronized     適合鎖少許的代碼同步問題,Lock  適合鎖大量的同步代碼! 

鎖是什麼呢,如何判斷鎖是誰?

四、生產者和消費者問題

面試的:單例模式、排序算法、生產者和消費者、死鎖

生產者和消費者問題 Synchronized   版

/**
 * 線程之間的通訊問題:生產者和消費者問題!  等待喚醒,通知喚醒
 * 線程交替執行  A   B 操做同一個變量   num = 0
 * A num+1
 * B num-1
 */
public class A {
    public static void main(String[] args) {
        Data data = new Data();

        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"A").start();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"B").start();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"C").start();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"D").start();
    }
}
// 判斷等待,業務,通知
class Data{ // 數字 資源類
    private int number = 0;
    //+1
    public synchronized void increment() throws InterruptedException {
        if (number!=0){  //0
            // 等待
            this.wait();
        }
        number++;
        System.out.println(Thread.currentThread().getName()+"=>"+number);
        // 通知其餘線程,我+1完畢了
        this.notifyAll();
    }
    //-1
    public synchronized void decrement() throws InterruptedException {
        if (number==0){ // 1
            // 等待
            this.wait();
        }
        number--;
        System.out.println(Thread.currentThread().getName()+"=>"+number);
        // 通知其餘線程,我-1完畢了
        this.notifyAll();
    }
}

問題存在,A  B  C D  4 個線程! 虛假喚醒,注意要把 if 判斷改成 while ,由於 if 只會判斷一次!

JUC版的生產者和消費者問題

經過Lock找到Condition

代碼實現:

public class B  {
    public static void main(String[] args) {
        Data2 data = new Data2();

        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"A").start();

        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"B").start();

        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"C").start();

        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"D").start();

    }
}
// 判斷等待,業務,通知
class Data2{ // 數字 資源類

    private int number = 0;
    Lock lock = new ReentrantLock();
    Condition condition = lock.newCondition();

    //condition.await(); // 等待
    //condition.signalAll(); // 喚醒所有
    //+1
    public void increment() throws InterruptedException {
        lock.lock();
        try {
            // 業務代碼
            while (number!=0){  //0
                // 等待
                condition.await();
            }
            number++;
            System.out.println(Thread.currentThread().getName()+"=>"+number);
            // 通知其餘線程,我+1完畢了
            condition.signalAll();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
    //-1
    public synchronized void decrement() throws InterruptedException {
        lock.lock();
        try {
            while (number==0){ // 1
                // 等待
                condition.await();
            }
            number--;
            System.out.println(Thread.currentThread().getName()+"=>"+number);
            // 通知其餘線程,我-1完畢了
            condition.signalAll();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

任何一個新的技術,絕對不是僅僅只是覆蓋了原來的技術,優點和補充!

Condition 精準的通知和喚醒線程

/**
 * A 執行完調用B,B執行完調用C,C執行完調用A
 */
public class C {

    public static void main(String[] args) {
        Data3 data = new Data3();

        new Thread(()->{
            for (int i = 0; i <10 ; i++) {
                data.printA();
            }
        },"A").start();

        new Thread(()->{
            for (int i = 0; i <10 ; i++) {
                data.printB();
            }
        },"B").start();

        new Thread(()->{
            for (int i = 0; i <10 ; i++) {
                data.printC();
            }
        },"C").start();
    }

}

class Data3{ // 資源類 Lock

    private Lock lock = new ReentrantLock();
    private Condition condition1 = lock.newCondition();
    private Condition condition2 = lock.newCondition();
    private Condition condition3 = lock.newCondition();
    private int number = 1; // 1A  2B  3C

    public void printA(){
        lock.lock();
        try {
            // 業務,判斷-> 執行-> 通知
            while (number!=1){
                // 等待
                condition1.await();
            }
            System.out.println(Thread.currentThread().getName()+"=>AAAAAAA");
            // 喚醒,喚醒指定的人,B
            number = 2;
            condition2.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void printB(){
        lock.lock();
        try {
            // 業務,判斷-> 執行-> 通知
            while (number!=2){
                condition2.await();
            }
            System.out.println(Thread.currentThread().getName()+"=>BBBBBBBBB");
            // 喚醒,喚醒指定的人,c
            number = 3;
            condition3.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
    public void printC(){
        lock.lock();
        try {
            // 業務,判斷-> 執行-> 通知
            // 業務,判斷-> 執行-> 通知
            while (number!=3){
                condition3.await();
            }
            System.out.println(Thread.currentThread().getName()+"=>BBBBBBBBB");
            // 喚醒,喚醒指定的人,c
            number = 1;
            condition1.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

本文參考:狂神說java

https://www.bilibili.com/video/av90007319

相關文章
相關標籤/搜索