多是東半球最好的多線程講義!

JAVA多線程java

多線程的基本概念算法

線程指進程中的一個執行場景,也就是執行流程,那麼進程和線程有什麼區別呢?編程

•    每一個進程是一個應用程序,都有獨立的內存空間windows

•    同一個進程中的線程共享其進程中的內存和資源(共享的內存是堆內存和方法區內存,棧內存不共享,每一個線程有本身的。)安全

什麼是進程?多線程

一個進程對應一個應用程序。例如:在windows操做系統啓動Word就表示啓動了一個併發

進程。在java的開發環境下啓動JVM,就表示啓動了一個進程。現代的計算機都是支持多異步

進程的,在同一個操做系統中,能夠同時啓動多個進程。ide

多進程有什麼做用?異步編程

單進程計算機只能作一件事情。

玩電腦,一邊玩遊戲(遊戲進程)一邊聽音樂(音樂進程)。

對於單核計算機來說,在同一個時間點上,遊戲進程和音樂進程是同時在運行嗎?不是。

由於計算機的CPU只能在某個時間點上作一件事。因爲計算機將在「遊戲進程」和「音樂

進程」之間頻繁的切換執行,切換速度極高,人類感受遊戲和音樂在同時進行。

多進程的做用不是提升執行速度,而是提升CPU的使用率。

進程和進程之間的內存是獨立的。

什麼是線程?

線程是一個進程中的執行場景。一個進程能夠啓動多個線程。

多線程有什麼做用?

多線程不是爲了提升執行速度,而是提升應用程序的使用率。

線程和線程共享「堆內存和方法區內存」,棧內存是獨立的,一個線程一個棧。

能夠給現實世界中的人類一種錯覺:感受多個線程在同時併發執行。

java程序的運行原理?

java命令會啓動java虛擬機,啓動JVM,等於啓動了一個應用程序,表示啓動了一個進程。該進程會自動啓動一個「主線程」,而後主線程去調用某個類的main方法。因此main方法運行在主線程中。在此以前的全部程序都是單線程的。

線程生命週期

線程是一個進程中的執行場景,一個進程能夠啓動多個線程

新建:採用new語句建立完成

就緒:執行start後

運行:佔用CPU時間

阻塞:執行了wait語句、執行了sleep語句和等待某個對象鎖,等待輸入的場合

終止:退出run()方法

多線程不是爲了提升執行速度,而是提升應用程序的使用率.

線程和線程共享」堆內存和方法區內存」.棧內存是獨立的,一個線程一個棧.

能夠給現實世界中的人類一種錯覺:感受多線程在同時併發執行.

不少人都對其中的一些概念不夠明確,如同步、併發等等,讓咱們先創建一個數據字典,以避免產生誤會。

•    多線程:指的是這個程序(一個進程)運行時產生了不止一個線程

•    並行與併發:

•    

o    並行:多個cpu實例或者多臺機器同時執行一段處理邏輯,是真正的同時。

•    

o    併發:經過cpu調度算法,讓用戶看上去同時執行,實際上從cpu操做層面不是真正的同時。併發每每在場景中有公用的資源,那麼針對這個公用的資源每每產生瓶頸,咱們會用TPS或者QPS來反應這個系統的處理能力。

線程安全:常常用來描繪一段代碼。指在併發的狀況之下,該代碼通過多線程使用,線程的調度順序不影響任何結果。這個時候使用多線程,咱們只須要關注系統的內存,cpu是否是夠用便可。反過來,線程不安全就意味着線程的調度順序會影響最終結果,如不加事務的轉帳代碼:

    voidtransferMoney(Userfrom,Userto,floatamount){

        to.setMoney(to.getBalance()+amount);

        from.setMoney(from.getBalance()-amount);

    }

同步:Java中的同步指的是經過人爲的控制和調度,保證共享資源的多線程訪問成爲線程安全,來保證結果的準確。如上面的代碼簡單加入@synchronized關鍵字。在保證結果準確的同時,提升性能,纔是優秀的程序。線程安全的優先級高於性能。

Java命令會啓動Java虛擬機,啓動JVM,等於啓動了一個應用程序,表示啓動了一個進程,該進程會自動啓動一個」主線程」,

而後主線程去調用某個類的main()方法,因此main()方法運行在主線程中.

線程的調度與控制

線程的調度模型分爲:分時調度模型和搶佔式調度模型,Java使用搶佔式調度模型

一般咱們的計算機只有一個CPU,CPU在某一個時刻只能執行一條指令,線程只有獲得CPU時間片,也就是使用權,才能夠執行指令。在單CPU的機器上線程不是並行運行的,只有在多個CPU上線程才能夠並行運行。Java虛擬機要負責線程的調度,取得CPU的使用權,目前有兩種調度模型:分時調度模型和搶佔式調度模型,Java使用搶佔式調度模型。分時調度模型:全部線程輪流使用CPU的使用權,平均分配每一個線程佔用CPU的時間片搶佔式調度模型:優先讓優先級高的線程使用CPU,若是線程的優先級相同,那麼會隨機選擇一個,優先級高的線程獲取的CPU時間片相對多一些。

    分時調度模型:全部線程輪流使用CPU的使用權,平均分配每一個線程佔用CPU的時間片

    搶佔式調度模型:優先讓優先級高的線程使用CPU,若是線程的優先級相同,那麼會隨機選擇一個,優先級高的線程獲取的CPU時間片相對多一些.

publicclassThreadTest{

    publicstaticvoidmain(String[]args){

        ThreadTest1();

        //ThreadTest2();

        //ThreadTest3();

        //ThreadTest4();

        //ThreadTest5();

    }

    /**

    *三個方法:獲取當前線程對象:Thread.currentThread();給線程起名:t1.setName("t1");獲取線程的名字:

    *t.getName();

    */

    privatestaticvoidThreadTest1(){

        Threadt=Thread.currentThread();//t保存的內存地址指向的線程爲"主線程"

        System.out.println(t.getId());

        Threadt1=newThread(newProcessor1());

        //給線程起名

        t1.setName("t1");

        t1.start();

        Threadt2=newThread(newProcessor1());

        t2.setName("t2");

        t2.start();

    }

    /**

    *線程優先級高的獲取的CPU時間片相對多一些優先級:1-10最低:1最高:10默認:5

    */

    privatestaticvoidThreadTest2(){

        Threadt1=newProcessor2();

        Threadt2=newProcessor2();

        t1.setName("t1");

        t2.setName("t2");

        System.out.println(t1.getPriority());

        System.out.println(t2.getPriority());

        t1.setPriority(1);

        t2.setPriority(10);

        t1.start();

        t2.start();

    }

    /**

    *1.Thread.sleep(毫秒);2.sleep方法是一個靜態方法3.該方法的做用:阻塞當前線程,騰出CPU,讓給其它線程

    */

    privatestaticvoidThreadTest3(){

        Threadt=newThread(newProcessor3());

        t.start();

        for(inti=0;i<11;i++){

            System.out.println(Thread.currentThread().getName()+"========>"

                    +i);

            try{

                t.sleep(5000);//等同於Thread.sleep(5000);阻塞的仍是當前線程,和t線程無關.

            }catch(InterruptedExceptione){

                e.printStackTrace();

            }

        }

    }

    /**

    *某線程正在休眠,如何打斷它的休眠如下方式依靠的是異常處理機制

    */

    privatestaticvoidThreadTest4(){

        try{

            Threadt=newThread(newProcessor4());

            t.start();

            Thread.sleep(5000);//睡5s

            t.interrupt();//打斷Thread的睡眠

        }catch(InterruptedExceptione){

            e.printStackTrace();

        }

    }

    /**

    *如何正確的更好的終止一個正在執行的線程需求:線程啓動5s以後終止.

    */

    privatestaticvoidThreadTest5(){

        Processor5p=newProcessor5();

        Threadt=newThread(p);

        t.start();

        //5s以後終止

        try{

            Thread.sleep(5000);

            p.isRun=false;

        }catch(InterruptedExceptione){

            //TODOAuto-generatedcatchblock

            e.printStackTrace();

        }

    }

}

classProcessor1implementsRunnable{

    @Override

    publicvoidrun(){

        Threadt=Thread.currentThread();//t保存的內存地址指向的線程爲"t1線程對象"

        System.out.println(t.getName());

        System.out.println(t.getId());

    }

}

classProcessor2extendsThread{

    @Override

    publicvoidrun(){

        for(inti=0;i<50;i++){

            System.out.println(Thread.currentThread().getName()

                    +"----------->"+i);

        }

    }

}

classProcessor3implementsRunnable{

    /**

    *Thread中的run方法不能拋出異常,因此重寫runn方法以後,在run方法的聲明位置上不能使用throws

    *因此run方法中的異常只能try...catch...

    */

    @Override

    publicvoidrun(){

        for(inti=0;i<11;i++){

            System.out.println(Thread.currentThread().getName()+"========>"

                    +i);

            try{

                Thread.sleep(1000);

            }catch(InterruptedExceptione){

                e.printStackTrace();

            }

        }

    }

}

classProcessor4implementsRunnable{

    @Override

    publicvoidrun(){

        try{

            Thread.sleep(1000000000);

            System.out.println("可否執行這裏");

        }catch(InterruptedExceptione){

            e.printStackTrace();

        }

        for(inti=0;i<11;i++){

            System.out.println(Thread.currentThread().getName()+"========>"

                    +i);

        }

    }

}

classProcessor5implementsRunnable{

    booleanisRun=true;

    @Override

    publicvoidrun(){

        for(inti=0;i<11;i++){

            if(isRun){

                try{

                    Thread.sleep(1000);

                }catch(InterruptedExceptione){

                    e.printStackTrace();

                }

                System.out.println(Thread.currentThread().getName()

                        +"========>"+i);

            }

        }

    }

}

線程優先級

線程優先級主要分三種:MAX_PRIORITY(最高);MIN_PRIORITY(最低級)NORM_PRIORITY(標準)默認

//設置線程的優先級,線程啓動後不能再次設置優先級

//必須在啓動前設置優先級

//設置最高優先級

t1.setPriority(Thread.MAX_PRIORITY);

sleep    

publicclassSleepTest{

    publicstaticvoidmain(String[]args){

        System.out.println("Wait");

        //讓主線程等待5秒再執行

        Wait.bySec(5);

        //提示恢復執行

        System.out.println("start");

    }

}

classWait{

    publicstaticvoidbySec(longs){

        //sleeps個1秒

        for(inti=0;i<s;i++){

            System.out.println(i+1+"秒");

            try{

                //sleep1秒

                Thread.sleep(1000);

            }catch(InterruptedExceptione){

                e.printStackTrace();

            }

        }

    }

}

中止一個線程

    若是咱們的線程正在睡眠,能夠採用interrupt進行中斷

    一般定義一個標記,來判斷標記的狀態中止線程的執行

yield

它與sleep()相似,只是不能由用戶指定暫停多長時間,而且yield()方法只能讓同優先級的線程有執行的機會,採用yieid能夠將CPU的使用權讓給同一個優先級的線程

publicclassYieldTest{

    publicstaticvoidmain(String[]args){

        FirstThreadmt=newFirstThread();

    SecThreadmnt=newSecThread();

    mt.start();

    mnt.start();

    }

}

classFirstThreadextendsThread{

    publicvoidrun(){

    for(inti=0;i<5;i++){

    System.out.println("第一個線程的第"+(i+1)+"次運行");

    Thread.yield();//暫停線程

    }

    }

}

classSecThreadextendsThread{

publicvoidrun(){

    for(inti=0;i<5;i++){

    System.out.println("第二個線程的第"+(i+1)+"次運行");

    Thread.yield();

    }

    }

}

join

當前線程能夠調用另外一個線程的join方法,調用後當前線程會被阻塞再也不執行,直到被調用的線程執行完畢,當前線程纔會執行

publicclassJoinTestextendsThread{

    publicJoinTest(Stringname){

        super(name);

    }

    publicvoidrun(){

        for(inti=0;i<5;i++)

            System.out.println(getName()+""+i);

    }

    publicstaticvoidmain(String[]args){

        for(inti=0;i<10;i++){

            if(i==5){

                JoinTesttempjt=newJoinTest("半路加入的線程");

                try{

                    tempjt.start();

                    tempjt.join();

                }catch(InterruptedExceptione){

                    e.printStackTrace();

                }

            }

            System.out.println(Thread.currentThread().getName()+""+i);

        }

    }

}

synchronized

線程同步,指某一個時刻,指容許一個線程來訪問共享資源,線程同步實際上是對對象加鎖,若是對象中的方法都是同步方法,那麼某一時刻只能執行一個方法,採用線程同步解決以上的問題,咱們只要保證線程一操做s時,線程2不容許操做便可,只有線程一使用完成s後,再讓線程二來使用s變量

•    異步編程模型:t1線程執行t1的,t2線程執行t2的,兩個線程之間誰也不等誰.

•    同步編程模型:t1線程和t2線程執行,t2線程必須等t1線程執行結束以後,t2線程才能執行,這是同步編程模型.

•    

•    何時要用同步呢?爲何要引入線程同步呢?

•    1.爲了數據的安全,儘管應用程序的使用率下降,可是爲了保證數據是安全的,必須加入線程同步機制.

•    線程同步機制使程序變成了(等同)單線程.

•    2.什麼條件下要使用線程同步?

•    第一:必須是多線程環境

•    第二:多線程環境共享同一個數據.

•    第三:共享的數據涉及到修改操做.

    //synchronized是對對象加鎖

    //採用synchronized同步最好只同步有線程安全的代碼

    //能夠優先考慮使用synchronized同步塊

    //由於同步的代碼越多,執行的時間就會越長,其餘線程等待的時間就會越長

    //影響效率

publicclassTestWithdrawal{

    publicstaticvoidmain(String[]args){

        //建立兩個線程

        TestAccountr=newTestAccount();

        Threadone=newThread(r);

        Threadtwo=newThread(r);

        one.setName("張三");

        two.setName("張三的妻子");

        //啓動線程

        one.start();

        two.start();

    }

}

classAccount{

    privateintbalance=500;//餘額

    publicintgetBalance(){

        returnbalance;

    }

    //取款

    publicvoidwithdraw(intamount){

        balance=balance-amount;

    }

}

classTestAccountimplementsRunnable{

    //全部用TestAccount對象建立的線程共享同一個賬戶對象

    privateAccountacct=newAccount();

    publicvoidrun(){

        for(inti=0;i<5;i++){

            makeWithdrawal(100);//取款

            if(acct.getBalance()<0){

                System.out.println("帳戶透支了!");

            }

        }

    }

    privatevoidmakeWithdrawal(intamt){

        synchronized(acct){

            if(acct.getBalance()>=amt){

                System.out.println(Thread.currentThread().getName()+"準備取款");

                try{

                    Thread.sleep(500);//0.5秒後實現取款

                }catch(InterruptedExceptionex){

                }

                //若是餘額足夠,則取款

                acct.withdraw(amt);

                System.out.println(Thread.currentThread().getName()+"完成取款,餘額:"+acct.getBalance());

            }else{

                //餘額不足給出提示

                System.out.println("餘額不足以支付"

                        +Thread.currentThread().getName()+"的取款,餘額爲"

                        +acct.getBalance());

            }

        }

    }

}

死鎖

publicclassDeadLock{

    publicstaticvoidmain(String[]args){

        Objecto1=newObject();

        Objecto2=newObject();

        Threadt1=newThread(newT1(o1,o2));

        Threadt2=newThread(newT2(o1,o2));

        t1.start();

        t2.start();

    }

}

classT1implementsRunnable{

    Objecto1;

    Objecto2;

    T1(Objecto1,Objecto2){

        this.o1=o1;

        this.o2=o2;

    }

    @Override

    publicvoidrun(){

        synchronized(o1){

            try{

                Thread.sleep(1000);

            }catch(InterruptedExceptione){

                e.printStackTrace();

            }

            synchronized(o2){

            }

        }

    }

}

classT2implementsRunnable{

    Objecto1;

    Objecto2;

    T2(Objecto1,Objecto2){

        this.o1=o1;

        this.o2=o2;

    }

    @Override

    publicvoidrun(){

        synchronized(o2){

            try{

                Thread.sleep(1000);

            }catch(InterruptedExceptione){

                e.printStackTrace();

            }

            synchronized(o1){

            }

        }

    }

}

守護線程

從線程分類上能夠分爲:用戶線程(以上講的都是用戶線程),另外一個是守護線程。守護線程是這樣的,全部的用戶線程結束生命週期,守護線程纔會結束生命週期,只要有一個用戶線程存在,那麼守護線程就不會結束,例如java中著名的垃圾回收器就是一個守護線程,只有應用程序中全部的線程結束,它纔會結束。

•    其它全部的用戶線程結束,則守護線程退出!

•    守護線程通常都是無限執行的.

publicclassDaemonThread{

    publicstaticvoidmain(String[]args)throwsInterruptedException{

        Threadt1=newThread(newRunnable2());

        t1.setName("t1");

        //將t1這個用戶線程修改爲守護線程.在線程沒有啓動時能夠修改如下參數

        t1.setDaemon(true);

        t1.start();

        //主線程

        for(inti=0;i<10;i++){

            System.out.println(Thread.currentThread().getName()+"----->"+i);

            Thread.sleep(1000);

        }

    }

}

classRunnable2implementsRunnable{

    @Override

    publicvoidrun(){

        inti=0;

        while(true){

            i++;

            System.out.println(Thread.currentThread().getName()+"-------->"

                    +i);

            try{

                Thread.sleep(500);

            }catch(InterruptedExceptione){

                e.printStackTrace();

            }

        }

    }

}

設置爲守護線程後,當主線程結束後,守護線程並無把全部的數據輸出完就結束了,也便是說守護線程是爲用戶線程服務的,當用戶線程所有結束,守護線程會自動結束

Timer.schedule()

/**

*關於定時器的應用做用:每隔一段固定的時間執行一段代碼

*/

publicclassTimerTest{

    publicstaticvoidmain(String[]args)throwsParseException{

        //1.建立定時器

        Timert=newTimer();

        //2.指定定時任務

        t.schedule(newLogTimerTask(),newSimpleDateFormat(

                "yyyy-MM-ddHH:mm:ssSSS").parse("2017-06-2914:24:00000"),

                10*1000);

    }

}

//指定任務

classLogTimerTaskextendsTimerTask{

    @Override

    publicvoidrun(){

        System.out.println(newSimpleDateFormat("yyyy-MM-ddHH:mm:ssSSS")

                .format(newDate()));

    }

}

 

我是melon,一個10年編程老司機。Q我3474203856。 給melon留言或者說明是看到文章過來的。全部相關技術問題均可以一塊兒尋找到答案。

相關文章
相關標籤/搜索