多線程2019-08-19

目的:多線程是知識(shí)體系中一重要的部分,使用多線程能同步完成多個(gè)任務(wù),提高資源使用效率進(jìn)而提高系統(tǒng)的效率。

線程所需掌握知識(shí)點(diǎn):

  • 1.如何創(chuàng)建一個(gè)線程 Thead Runnable
  • 2.線程的同步
  • 3.主線程與子線程之間使用接口回調(diào)數(shù)據(jù)
  • 4.線程之間的通信 :
    synchronized (wait notify notifyALL)

ReentrantLock lock;
Condition c = lock.newCondition()
await single singleALL

技術(shù):

1.基本知識(shí)點(diǎn):

(1)進(jìn)程和線程

進(jìn)程:正在運(yùn)行的一個(gè)程序QQ IDE 瀏覽器
系統(tǒng)會(huì)為這個(gè)進(jìn)程分配獨(dú)立的內(nèi)存資源
線程:具體執(zhí)行任務(wù)的最小單位
一個(gè)進(jìn)程最少擁有一個(gè)線程(主線程 運(yùn)行起來就執(zhí)行的線程)
線程之間是共享內(nèi)存資源的(進(jìn)程申請的)
線程之間可以通信(數(shù)據(jù)傳遞:多數(shù)情況下為主線程和子線程)
每一個(gè)線程都有自己的回路(生命周期)

(2)線程的生命周期 狀態(tài)
6441157D1DFF7B3DA414078385811477.jpg
     NEW:新建 線程剛被創(chuàng)建好
     RUNNABLE: runnable 就緒狀態(tài) 只要搶到時(shí)間片就可以運(yùn)行這個(gè)線程
     BLOCKED :阻塞狀態(tài)  sleep
     WAITING :等待     wait
     TIMED_WAITING
     TERMINATED :終止
(3)為什么需要?jiǎng)?chuàng)建子線程

如果在主線程中存在比較耗時(shí)的操作:下載視頻 上傳文件 數(shù)據(jù)處理
這些操作會(huì)阻塞主線程 后面的任務(wù)必須等這些任務(wù)執(zhí)行完畢
之后才能執(zhí)行,用戶體驗(yàn)感差
為了不阻塞主線程,需要將耗時(shí)的任務(wù)放在子線程里面去執(zhí)行

2.如何創(chuàng)建子線程:

(1)寫一個(gè)類繼承于Thread 實(shí)現(xiàn)run方法
  • join: 讓當(dāng)前這個(gè)線程阻塞,讓join的線程執(zhí)行完畢再執(zhí)行
  • setName:設(shè)置線程名稱
  • getName:獲取線程名稱
  • currentThread:獲取當(dāng)前線程的線程對象
  • start:開啟任務(wù)
    eg:
class TextTHread extends Thread{
    //實(shí)現(xiàn)run方法
    //方法里面就是具體需要執(zhí)行的代碼
    @Override
    public void run(){
        String name = Thread.currentThread().getName();
        for (int i = 0; i < 100; i++) {
            System.out.println(name+":"+(i+1));
           
        }
        super.run();
    }
}

創(chuàng)建線程:

 //main方法里面執(zhí)行的代碼 是在主線程里面執(zhí)行的
        //主線程的名稱是main (不是main方法)
        //System.out.println(Thread.currentThread().getName());

        //創(chuàng)建Thread對象
        TextTHread textTHread1 = new TextTHread();
        //設(shè)置線程名稱
        textTHread1.setName("子線程1");
        //開啟任務(wù)
        textTHread1.start();

        textTHread2 = new TextTHread();
        //設(shè)置線程名稱
        textTHread2.setName("子線程2");
        //開啟任務(wù)
        textTHread2.start();
(2).實(shí)現(xiàn)Runnable接口 實(shí)現(xiàn)run方法
  • a.創(chuàng)建任務(wù) 創(chuàng)建類實(shí)現(xiàn)Runnable接口
  • b.使用Thread 為這個(gè)任務(wù)分配線程
  • c.開啟任務(wù) start
    eg:
class PXDThread implements Runnable{
    @Override
    public void run() {
        for (int i = 1; i <=100; i++) {
            System.out.println(Thread.currentThread().getName()+i);
        }
    }
}

調(diào)用方法1:

//2.1
        PXDThread pt = new PXDThread();
        //使用Thread操作這個(gè)任務(wù)
        Thread t = new Thread(pt);

        t.setName("子線程1:");
        t.start();

        Thread t2 = new Thread(pt);//一個(gè)任務(wù)可以由多個(gè)線程完成啊
        t2.setName("子線程2:");
        t2.start();

調(diào)用方法2:

 //2.2
        //這個(gè)任務(wù)只需要使用一次
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 1; i <=100; i++) {
                    System.out.println(Thread.currentThread().getName()+i);
                }
            }
        });
        t1.setName("子線程1:");
        t1.start();

調(diào)用方法3:

//2.3
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 1; i <=100; i++) {
                    System.out.println(Thread.currentThread().getName()+i);
                }
            }
        }).start();

調(diào)用方法4:

 //2.4
        //使用Lambda表達(dá)式
        //不建議 閱讀性太差
        new Thread( () -> {
            for (int i = 1; i <=100; i++) {
                System.out.println(Thread.currentThread().getName() + i);
            }
        }).start();

3.線程安全:同步

    線程安全  synchronized Lock  加鎖解鎖
    synchronized 需要同步監(jiān)聽器 需要一把鎖
    任何對象都有一個(gè)把鎖
    如果多個(gè)線程操作同一一個(gè)代碼塊,并且需要同步
    那么就需要操作同一個(gè)對象/同一個(gè)對象的同一把鎖
    synchronized(監(jiān)聽器/對象/鎖)

eg:火車票賣票 全國的賣票系統(tǒng)就一個(gè)

(1)synchronized:

synchronized(監(jiān)聽器/對象/鎖)
1.同步代碼塊
synchronized(監(jiān)聽器/對象/鎖){
需要同步的代碼
}

//用于賣票的任務(wù)
class Ticket implements Runnable{
    //定義所有車票的數(shù)量
    public static  int num = 100;
    String name;
    public Ticket(String name){
        this.name = name;
    }
    static final Object obj =new Object();

    //創(chuàng)建一個(gè)可重新載入的鎖
    static ReentrantLock lock = new ReentrantLock();

    public void run() {
        for(int i =1;i<=100;i++){
            //判斷有沒有票
            synchronized (obj){
                //需要同步的代碼
                if (num>0){
                    System.out.println(name+"出票:"+(101-num));
                    num--;
                    try {
                        //當(dāng)前線程等待
                        obj.notify();
                        obj.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }else{
                    break;
                }
            }

        }
    }
}
(2)Lock:

2.同步方法 同步監(jiān)聽器就是當(dāng)前對象本身
必須保證多個(gè)對象調(diào)用的同步方法時(shí)操作的統(tǒng)一對象
public synchronized void text(){
本質(zhì)就是同步代碼塊
等價(jià)于
synchronized(this) {
text();
}

以下代碼中未實(shí)現(xiàn)await single singleALL等線程狀態(tài)轉(zhuǎn)換方法

//用于賣票的任務(wù)
class Ticket implements Runnable{
    //定義所有車票的數(shù)量
    public static  int num = 100;
    String name;
    public Ticket(String name){
        this.name = name;
    }
    static final Object obj =new Object();

    //創(chuàng)建一個(gè)可重新載入的鎖
    static ReentrantLock lock = new ReentrantLock();

    Condition condition = lock.newCondition();
    public void run() {
        for(int i =1;i<=100;i++){
            //判斷有沒有票
//            synchronized (obj){
//                //需要同步的代碼
            //加鎖
            lock.lock();
                if (num>0){
                    System.out.println(name+"出票:"+(101-num));
                    num--;
                    lock.newCondition();
                }else{
                    break;
                }
            //解鎖
            lock.unlock();
        }
    }
}

調(diào)用:

//        火車票賣票
//        全國的賣票系統(tǒng)就一個(gè)
        Ticket ticketCQ = new Ticket("重慶");
        Thread t1 = new Thread(ticketCQ);
        t1.start();

        Ticket ticketSH = new Ticket("上海");
        Thread t2 = new Thread(ticketSH);
        t2.start();

運(yùn)行結(jié)果太長,不予展現(xiàn)。

4.使用接口實(shí)現(xiàn)線程之間數(shù)據(jù)回調(diào)

(1)定義線程里面 Agent類
public class Agent extends Thread{
    AgentInterface target;

    @Override
    public void run() {
        System.out.println("開始找房子");
        System.out.println("---------");
        System.out.println("房子找到了 即將返回?cái)?shù)據(jù)");

        target.callBack("房子在XXX");
        super.run();
    }

    public interface AgentInterface{
        void callBack(String desc);
    }

}
(2)定義Person類:
public class Person implements Agent.AgentInterface {


    public void needHouse(){

        Agent xw = new Agent();
        xw.target = this;   //表明返回?cái)?shù)據(jù)給調(diào)用者
        xw.start();
    }

    @Override
    public void callBack(String desc) {
        System.out.println("我是小王,接受到你的數(shù)據(jù)"+desc);
    }
}
(3)調(diào)用:
 Person person = new Person();
        person.needHouse();
運(yùn)行結(jié)果:
開始找房子
---------
房子找到了 即將返回?cái)?shù)據(jù)
我是小王,接受到你的數(shù)據(jù)房子在XXX

Process finished with exit code 0

心得:

java的學(xué)習(xí)要接近尾聲了,我越來越認(rèn)識(shí)到自己前面的知識(shí)點(diǎn)有些力不從心,比如代理設(shè)計(jì)模式,哎,得好好去復(fù)習(xí)了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容