麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 學院 > 開發設計 > 正文

基礎學習day11--多線程一線程的創建,運行,同步和鎖

2019-11-14 15:37:17
字體:
來源:轉載
供稿:網友

一、線程基本概述

1.1、進程和線程

進程:一個應用程序一般都是一個進程,正在進行的程序

 

每一個進程最少都有一個線程,都有一個執行順序,該順序是一個執行路徑或者一個控制單元

 

線程:進程中一個獨立的控制單元,線程控制著進程的執行。

 

windows中的任務管理器,可以查看進程,linux下通過ps命令

線程是進程的最小單位

線程依賴于進程

線程隨著進程的創建和創建,隨著進程的結束而消亡

迅雷:可以同時開啟多個下載,就是多線程

多個程序同時執行,時CPU在很快的切換,看上去是同時執行,實際上是在CPU在切換執行。

多線程存在的意義:可以讓程序中的內容同時執行。

 

二、繼承線程的創建

2.1、繼承Thread,重寫run方法

 

package com.pb.thread.demo1;/** *  * @author Denny * 繼承Thread 類并重寫run方法來創建線程類 * */public class MyThread extends Thread {        PRivate int count;        /*     * 重寫run 方法     * @see java.lang.Thread#run()     */    @Override    public void run(){        /*         * 要運行的代碼塊或者方法,在這里調用,或者直接寫在這里         */        while(count<10){        count++;        System.out.println("My thread run方法啟動了"+count);        }    }   public static void main(String[] args) {       //聲明線程類       MyThread mt=new MyThread();       //啟動線程,JVM調用run方法       mt.start();       //主線程       for(int x=0;x<10;x++){          System.out.println("main thread"+x);       }}        }

 

多個線程都在搶占CPU的執行權,誰搶到,誰就執行

在某一時刻,只能有一個程序在運行

CPU在做著快速切換,以達到看上去是同時運行的效果。

多線程一個特性:隨機性,誰搶到誰執行.

 

 

三、線程的運行和線程狀態

3.1、調用start()方法

使該線程開始執行,Java虛擬機調用該線程的run()方法

為什么要重寫run方法.

Thread類用于描述線程。

這個類定義一個功能,用于存儲線程要運行的代碼。該存儲功能就是run方法.

也就是說,Thread類中的run方法是用于存儲線程要運行的代碼

如果直接調用run()方法,就是調用對象的普通方法一樣.,僅僅是對象調用方法.線程創建了并沒有運行。

只有start()才可以運行線程。

3.2、線程狀態

新生:創建線程 new Thread()或者子類

運行:正在運行的線程,調用start()方法

凍結:已經創建的線程,但非運行狀態的線程。sleep(long 毫秒), wait()線程等待,直到notify()喚醒才可以繼續運行

臨時狀態阻塞:具備運行資格,但沒有執行權,就是還沒有被CPU切換到.

消亡:線程死亡stop(),或者線程運行完成。

 

 

 

四、獲取線程對象

4.1、獲取當前線程對象和名稱

繼承thread類實現線程,局部變量都有單獨的一份不能共享數據

 

package com.pb.thread.demo1;/** *  * @author Denny * 繼承Thread 類并重寫run方法來創建線程類 *Thread.currentThread(),獲取當前線程對象 *繼承thread類實現線程,局部變量都有單獨的一份不能共享數據 */public class MyThread extends Thread {        public MyThread(String name){        super(name);    }    /*     * 重寫run 方法     * @see java.lang.Thread#run()     */    @Override    public void run(){        /*         * 要運行的代碼塊或者方法,在這里調用,或者直接寫在這里         */        for(int x=0;x<10;x++){                System.out.println("My thread run的名字:"+Thread.currentThread().getName()+","+x);        }    }   public static void main(String[] args) {       //聲明線程類       MyThread mt1=new MyThread("mt1");      // mt1.setName("張三"); 設置線程名稱       MyThread mt2=new MyThread("mt2");       //啟動線程,JVM調用run方法       mt1.start();       mt2.start();       //主線程       for(int x=0;x<10;x++){          System.out.println(currentThread().getName()+","+x);       }}        }

 

示例:

 

 

五、接口實現線程

5.1、實現Runnable接口

重寫run方法()

實現接口的方式最大的好處是可以共享數據

示例:多窗口同時售票,

 

package com.pb.thread.demo1;/** *  * @author Administrator 多個窗口同時賣票 *  */public class Ticket implements Runnable {    private  int tick = 100;    public void run() {        while (true) {            if (tick > 0) {                System.out.println(Thread.currentThread().getName()+"賣:" + tick--);            }else{                break;            }        }    }    public static void main(String[] args) {        //聲明線程類        Ticket ticket=new Ticket();        //創建線程對象,并將類做為參數        Thread t1=new Thread(ticket);        t1.setName("一號窗口,");        Thread t2=new Thread(ticket);        t2.setName("二號窗口,");        Thread t3=new Thread(ticket);        t3.setName("三號窗口,");        Thread t4=new Thread(ticket);        t4.setName("四號窗口,");        t1.start();        t2.start();        t3.start();        t4.start();                    }}

 

結果:

  1 一號窗口,賣:100  2 一號窗口,賣:98  3 一號窗口,賣:97  4 一號窗口,賣:96  5 一號窗口,賣:95  6 一號窗口,賣:94  7 二號窗口,賣:99  8 二號窗口,賣:92  9 一號窗口,賣:93 10 一號窗口,賣:88 11 一號窗口,賣:87 12 一號窗口,賣:86 13 二號窗口,賣:89 14 二號窗口,賣:84 15 二號窗口,賣:83 16 二號窗口,賣:82 17 二號窗口,賣:81 18 二號窗口,賣:80 19 二號窗口,賣:79 20 二號窗口,賣:78 21 二號窗口,賣:77 22 二號窗口,賣:76 23 二號窗口,賣:75 24 二號窗口,賣:74 25 二號窗口,賣:73 26 二號窗口,賣:72 27 二號窗口,賣:71 28 二號窗口,賣:70 29 二號窗口,賣:69 30 二號窗口,賣:68 31 二號窗口,賣:67 32 二號窗口,賣:66 33 二號窗口,賣:65 34 二號窗口,賣:64 35 二號窗口,賣:63 36 二號窗口,賣:62 37 二號窗口,賣:61 38 二號窗口,賣:60 39 二號窗口,賣:59 40 二號窗口,賣:58 41 二號窗口,賣:57 42 二號窗口,賣:56 43 二號窗口,賣:55 44 二號窗口,賣:54 45 二號窗口,賣:53 46 二號窗口,賣:52 47 二號窗口,賣:51 48 二號窗口,賣:50 49 二號窗口,賣:49 50 二號窗口,賣:48 51 二號窗口,賣:47 52 二號窗口,賣:46 53 二號窗口,賣:45 54 二號窗口,賣:44 55 二號窗口,賣:43 56 二號窗口,賣:42 57 二號窗口,賣:41 58 二號窗口,賣:40 59 二號窗口,賣:39 60 二號窗口,賣:38 61 二號窗口,賣:37 62 二號窗口,賣:36 63 二號窗口,賣:35 64 二號窗口,賣:34 65 二號窗口,賣:33 66 二號窗口,賣:32 67 二號窗口,賣:31 68 二號窗口,賣:30 69 二號窗口,賣:29 70 二號窗口,賣:28 71 二號窗口,賣:27 72 二號窗口,賣:26 73 二號窗口,賣:25 74 二號窗口,賣:24 75 二號窗口,賣:23 76 二號窗口,賣:22 77 二號窗口,賣:21 78 三號窗口,賣:90 79 四號窗口,賣:91 80 三號窗口,賣:19 81 二號窗口,賣:20 82 一號窗口,賣:85 83 二號窗口,賣:16 84 三號窗口,賣:17 85 四號窗口,賣:18 86 三號窗口,賣:13 87 三號窗口,賣:11 88 三號窗口,賣:10 89 三號窗口,賣:9 90 三號窗口,賣:8 91 三號窗口,賣:7 92 三號窗口,賣:6 93 三號窗口,賣:5 94 三號窗口,賣:4 95 三號窗口,賣:3 96 三號窗口,賣:2 97 三號窗口,賣:1 98 二號窗口,賣:14 99 一號窗口,賣:15100 四號窗口,賣:12

 

 

兩種創建線程方式:

 

 

 優點   缺點
繼承Thread類

 1.編寫簡單  

2.可以使用this關鍵字直接訪問當前線程

無法繼承其它類

無法實現數據共享

實現Runnable接口

1.可以繼承其它類 

2.多個線程之間可以使用同一個Runnable對象

 3.可以共享數據

編程方式稍微復雜,如需訪問當前線程,需要調用Thread類的currentThread()方法                                                                                                              

                                   
                                 

 

六、線程安全

6.1、還是上面的例子

加上sleep(1000)睡覺1秒

 

package com.day10.thread.demo1;public class Ticket implements Runnable {    private int num=100;    @Override    public void run() {              while(true){            if(num>0){                try {                    Thread.sleep(1000);  //當前線程睡覺1秒,毫秒單位                } catch (InterruptedException e) {                    e.printStackTrace();                }                System.out.println(Thread.currentThread().getName()+",賣出"+num--+"號票");            }        }    }    public static void main(String[] args) {        Ticket t=new Ticket();        Thread t1=new Thread(t);        Thread t2=new Thread(t);        Thread t3=new Thread(t);        Thread t4=new Thread(t);        t1.start();        t2.start();        t3.start();        t4.start();    }}

 

結果:

Picked up JAVA_TOOL_OPTIONS: -javaagent:/usr/share/java/jayatanaag.jar Thread-0,賣出100號票Thread-2,賣出99號票Thread-1,賣出98號票Thread-3,賣出97號票Thread-0,賣出96號票Thread-2,賣出95號票Thread-1,賣出94號票Thread-3,賣出93號票Thread-0,賣出92號票Thread-2,賣出91號票Thread-1,賣出90號票Thread-3,賣出89號票Thread-0,賣出88號票Thread-2,賣出87號票Thread-1,賣出86號票Thread-3,賣出85號票Thread-0,賣出84號票Thread-2,賣出83號票Thread-1,賣出82號票Thread-3,賣出81號票Thread-0,賣出80號票Thread-2,賣出79號票Thread-1,賣出78號票Thread-3,賣出77號票Thread-0,賣出76號票Thread-2,賣出75號票Thread-1,賣出74號票Thread-3,賣出73號票Thread-0,賣出72號票Thread-2,賣出71號票Thread-1,賣出70號票Thread-3,賣出69號票Thread-0,賣出68號票Thread-2,賣出67號票Thread-1,賣出66號票Thread-3,賣出65號票Thread-0,賣出64號票Thread-2,賣出63號票Thread-1,賣出62號票Thread-3,賣出61號票Thread-0,賣出60號票Thread-2,賣出59號票Thread-1,賣出58號票Thread-3,賣出57號票Thread-0,賣出56號票Thread-2,賣出55號票Thread-1,賣出54號票Thread-3,賣出53號票Thread-0,賣出52號票Thread-2,賣出51號票Thread-1,賣出50號票Thread-3,賣出49號票Thread-0,賣出48號票Thread-2,賣出47號票Thread-1,賣出46號票Thread-3,賣出45號票Thread-0,賣出44號票Thread-2,賣出43號票Thread-1,賣出42號票Thread-3,賣出41號票Thread-0,賣出40號票Thread-2,賣出39號票Thread-1,賣出38號票Thread-3,賣出37號票Thread-0,賣出36號票Thread-2,賣出35號票Thread-1,賣出34號票Thread-3,賣出33號票Thread-0,賣出32號票Thread-2,賣出31號票Thread-1,賣出30號票Thread-3,賣出29號票Thread-0,賣出28號票Thread-2,賣出27號票Thread-1,賣出26號票Thread-3,賣出25號票Thread-0,賣出24號票Thread-2,賣出23號票Thread-1,賣出22號票Thread-3,賣出21號票Thread-0,賣出20號票Thread-2,賣出19號票Thread-1,賣出18號票Thread-3,賣出17號票Thread-0,賣出16號票Thread-2,賣出15號票Thread-1,賣出14號票Thread-3,賣出13號票Thread-0,賣出12號票Thread-2,賣出11號票Thread-1,賣出10號票Thread-3,賣出9號票Thread-0,賣出8號票Thread-2,賣出7號票Thread-1,賣出6號票Thread-3,賣出5號票Thread-0,賣出4號票Thread-2,賣出3號票Thread-1,賣出2號票Thread-3,賣出1號票Thread-0,賣出0號票Thread-2,賣出-1號票Thread-1,賣出-2號票

發現多賣票了,

為什么?因為賣票當前線程睡眠了1秒,其它線程就可以把這張票已經賣出了,

條件檢查1>0,如果4個人同時檢查,條件成立,就繼續賣票就出現了,負數

怎么解決?給線程加鎖

線程安全問題產生的原因:

    1. 多個線程在操作共享的數據。
    2. 操作共享數據的線程代碼有多條。
    當一個線程在執行操作共享數據的多條代碼過程中,其他線程參與了運算,就會導致線程安全問題的產生

解決方式:就是將多條操作共享數據的線程代碼封裝起來,當有線程在執行這些代碼的時候,其他線程不可以參與運算。必須要當前線程把這些代碼都執行完畢后,其他線程才可以參與運算。

看下面的同步synchronized

 

七、同步代碼塊

7.1、synchronized

同步代碼塊的格式:
    synchronized(對象){
           需要被同步的代碼;
    } 
    同步的好處:解決了線程的安全問題。
    同步的弊端:當線程相當多時,因為每個線程都會去判斷同步上的鎖,這是很耗費資源的,無形中會降低程序的運行效率。
    同步的前提:必須有多個線程并使用同一個鎖。

修改上面的代碼

 

package com.day10.thread.demo1;public class Ticket implements Runnable {    private int num=100;    @Override    public void run() {              while(true){            synchronized(this){            if(num>0){                try {                    Thread.sleep(1000);  //當前線程睡覺1秒,毫秒單位                } catch (InterruptedException e) {                    e.printStackTrace();                }                System.out.println(Thread.currentThread().getName()+",賣出"+num--+"號票");            }else{                break;            }            }        }    }    public static void main(String[] args) {        Ticket t=new Ticket();        Thread t1=new Thread(t);        Thread t2=new Thread(t);        Thread t3=new Thread(t);        Thread t4=new Thread(t);        t1.start();        t2.start();        t3.start();        t4.start();    }}

 

 

 

八、同步函數 

8.1、同步方法

 

package com.day10.thread.demo2;public class Account {        //余額    private double blance=500;            //取款    public void withDraw(int num){                blance=blance-num;             }    public double getBlance() {        return blance;    }    public void setBlance(double blance) {        this.blance = blance;    }        }package com.day10.thread.demo2;public class AccountThread implements Runnable {    private Account account=new Account();    @Override    public void run() {        for (int i = 0; i < 5; i++) {            if(account.getBlance()<0){                System.out.println("透支了!!");            }            makWithDraw(100); //每次取100        }    }        /*     * 取款的方法     */    public void makWithDraw(int num){        //判斷余額是不是大于要取款的數        if(account.getBlance()>=num){            System.out.println(Thread.currentThread().getName()+":準備取款!");            try {                Thread.sleep(1000); //等待1秒                account.withDraw(num);                System.out.println(Thread.currentThread().getName()+":取款完成!,當前余額為:"+account.getBlance());            } catch (InterruptedException e) {                e.printStackTrace();            }                                }else{            System.out.println(Thread.currentThread().getName()+"  余額不足以支付當前取款, 余額為:  "+account.getBlance());        }    }}package com.day10.thread.demo2;public class Demo {    public static void main(String[] args) {                AccountThread at=new AccountThread();        Thread t1=new Thread(at);        t1.setName("張三");        Thread t2=new Thread(at);        t2.setName("張三老婆");        t1.start();        t2.start();    }}

 

結果:

張三:準備取款!張三老婆:準備取款!張三:取款完成!,當前余額為:400.0張三:準備取款!張三老婆:取款完成!,當前余額為:300.0張三老婆:準備取款!張三:取款完成!,當前余額為:200.0張三:準備取款!張三老婆:取款完成!,當前余額為:100.0張三老婆:準備取款!張三:取款完成!,當前余額為:0.0張三  余額不足以支付當前取款, 余額為:  0.0張三  余額不足以支付當前取款, 余額為:  0.0張三老婆:取款完成!,當前余額為:-100.0透支了!!張三老婆  余額不足以支付當前取款, 余額為:  -100.0透支了!!張三老婆  余額不足以支付當前取款, 余額為:  -100.0

加上同步關鍵字

/*     * 取款的方法     */    public  synchronized void makWithDraw(int num){        //判斷余額是不是大于要取款的數        if(account.getBlance()>=num){            System.out.println(Thread.currentThread().getName()+":準備取款!");            try {                Thread.sleep(1000); //等待1秒                account.withDraw(num);                System.out.println(Thread.currentThread().getName()+":取款完成!,當前余額為:"+account.getBlance());            } catch (InterruptedException e) {                e.printStackTrace();            }                                }else{            System.out.println(Thread.currentThread().getName()+"  余額不足以支付當前取款, 余額為:  "+account.getBlance());        }    }

結果:

張三:準備取款!張三:取款完成!,當前余額為:400.0張三老婆:準備取款!張三老婆:取款完成!,當前余額為:300.0張三:準備取款!張三:取款完成!,當前余額為:200.0張三:準備取款!張三:取款完成!,當前余額為:100.0張三:準備取款!張三:取款完成!,當前余額為:0.0張三  余額不足以支付當前取款, 余額為:  0.0張三老婆  余額不足以支付當前取款, 余額為:  0.0張三老婆  余額不足以支付當前取款, 余額為:  0.0張三老婆  余額不足以支付當前取款, 余額為:  0.0張三老婆  余額不足以支付當前取款, 余額為:  0.0

沒有發生透支現象

同步代碼塊:

/*     * 取款的方法     */    public   void makWithDraw(int num){        synchronized(account){        //判斷余額是不是大于要取款的數        if(account.getBlance()>=num){            System.out.println(Thread.currentThread().getName()+":準備取款!");            try {                Thread.sleep(1000); //等待1秒                account.withDraw(num);                System.out.println(Thread.currentThread().getName()+":取款完成!,當前余額為:"+account.getBlance());            } catch (InterruptedException e) {                e.printStackTrace();            }                                }else{            System.out.println(Thread.currentThread().getName()+"  余額不足以支付當前取款, 余額為:  "+account.getBlance());        }        }    }

結果同上,沒有發生透支現象

 

同步函數和同步代碼塊的區別:
    1. 同步函數的鎖是固定的this。
    2. 同步代碼塊的鎖是任意的對象。
    建議使用同步代碼塊。

 

    由于同步函數的鎖是固定的this,同步代碼塊的鎖是任意的對象,那么如果同步函數和同步代碼塊都使用this作為鎖,就可以實現同步。

 

 

 

九、同步鎖

9.1、同鎖

 

同步方法同步對象是this,同步代碼塊也可以使用this來同步

十、靜態同步

10.1、靜態同步

不是this,因為靜態方法中也不可以定義this

靜態進內存,內存中沒有本類對象,但是一定有該類對應的字節碼文件對象

靜態的同步函數使用的鎖是該函數所屬字節碼文件對象,可以用getClass方法獲取,也可以用當前類名.class表示。

synchronizid(類名.class){  或者對象.getClass

}

十一、單例模式加上同步懶漢式

11.1、懶漢式加鎖

 

package com.day10.thread.demo2;/** *  * @author denny *單例模式 *餓漢式,不存在復生成對象的問題 *懶漢工,加synchronize */public class SingleDemo {    private static SingleDemo singleDemo;        private SingleDemo(){            }    public static SingleDemo getNewIntance(){        if(singleDemo==null){//判斷是不是空,不是空就直接返回,是空就加鎖            synchronized(SingleDemo.class){  //加鎖 //this.getClass() 直接寫對象singleDemo.getClass()也行                            if(singleDemo==null){                singleDemo=new SingleDemo();            }            }        }        return singleDemo;            }}

 

 

 

十二、死鎖

12.1、死鎖常見情景之一:同步的嵌套。

 

 class MyLock{     static  Object lockA=new Object();     static   Object lockB=new Object();}public class Demo implements Runnable {    private boolean flag;    public Demo(boolean flag) {        this.flag = flag;    }    @Override    public void run() {                    if (flag) {                while (true) {                synchronized (MyLock.lockA) {                    System.out.println("if.........lockA");                    synchronized (MyLock.lockB) {                        System.out.println("if.........lockB");                    }                }            }            }             else {                 while(true){                synchronized (MyLock.lockB) {                    System.out.println("else.........lockB");                    synchronized (MyLock.lockA) {                        System.out.println("else.........lockA");                    }                }                }            }        }    public static void main(String[] args) {        Thread t1 = new Thread(new Demo(true));        Thread t2 = new Thread(new Demo(false));        t1.start();        t2.start();    }}

 建議將要鎖的對象,聲明為static


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 午夜视频国产 | 蜜桃视频日韩 | 中文字幕极速在线观看 | 蜜桃网在线观看 | a网在线 | 国产精品高潮视频 | 免费专区 - 91爱爱 | 精品一区二区中文字幕 | 亚洲片在线观看 | 欧美成年私人网站 | 一区二区三区视频播放 | 中文字幕在线观看免费视频 | 成人一区二区三区在线 | 黄色av一区二区三区 | 久久久久亚洲a | 亚洲精品成人在线视频 | 天天色狠狠干 | 午夜伦情电午夜伦情电影 | 久久久久久久一区二区 | 久草在线公开视频 | 中文黄色一级片 | va免费视频 | 黄色羞羞视频在线观看 | 久久国产精品久久久久久久久久 | 中文字幕极速在线观看 | 精品成人免费视频 | 亚洲第一成人在线视频 | 国产色片在线观看 | 香蕉久草视频 | 免费黄色在线观看网站 | 在线观看国产免费视频 | 国产一区免费 | 日韩视频―中文字幕 | 午夜精品久久久久久久99热浪潮 | 日韩欧美高清片 | av成人在线电影 | 女人一级一级毛片 | 亚洲精中文字幕二区三区 | h视频免费看 | 新久草在线视频 | 性aaa|