27_多线程_第27天(线程安全、线程同步、等待唤醒机制、单例设计模式)_讲义...
生活随笔
收集整理的這篇文章主要介紹了
27_多线程_第27天(线程安全、线程同步、等待唤醒机制、单例设计模式)_讲义...
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
今日內容介紹
1、多線程安全問題
2、等待喚醒機制
01線程操作共享數據的安全問題
*A:線程操作共享數據的安全問題如果有多個線程在同時運行,而這些線程可能會同時運行這段代碼。程序每次運行結果和單線程運行的結果是一樣的,而且其他的變量的值也和預期的是一樣的,就是線程安全的。02售票的案例
*A:售票的案例
/** 多線程并發訪問同一個數據資源* 3個線程,對一個票資源,出售*/public class ThreadDemo {public static void main(String[] args) {//創建Runnable接口實現類對象Tickets t = new Tickets();//創建3個Thread類對象,傳遞Runnable接口實現類Thread t0 = new Thread(t);Thread t1 = new Thread(t);Thread t2 = new Thread(t);t0.start();t1.start();t2.start();}}public class Tickets implements Runnable{//定義出售的票源private int ticket = 100;private Object obj = new Object();public void run(){while(true){if( ticket > 0){System.out.println(Thread.currentThread().getName()+" 出售第 "+ticket--);}}}}03線程安全問題引發
*A:線程安全問題引發
/** 多線程并發訪問同一個數據資源* 3個線程,對一個票資源,出售*/ public class ThreadDemo {public static void main(String[] args) {//創建Runnable接口實現類對象Tickets t = new Tickets();//創建3個Thread類對象,傳遞Runnable接口實現類Thread t0 = new Thread(t);Thread t1 = new Thread(t);Thread t2 = new Thread(t);t0.start();t1.start();t2.start();} } /** 通過線程休眠,出現安全問題*/ public class Tickets implements Runnable{//定義出售的票源private int ticket = 100;private Object obj = new Object();public void run(){while(true){//對票數判斷,大于0,可以出售,變量--操作if( ticket > 0){try{Thread.sleep(10); //加了休眠讓其他線程有執行機會}catch(Exception ex){}System.out.println(Thread.currentThread().getName()+" 出售第 "+ticket--);}}} }04同步代碼塊解決線程安全問題
*A:同步代碼塊解決線程安全問題
*A:售票的案例/** 多線程并發訪問同一個數據資源* 3個線程,對一個票資源,出售*/public class ThreadDemo {public static void main(String[] args) {//創建Runnable接口實現類對象Tickets t = new Tickets();//創建3個Thread類對象,傳遞Runnable接口實現類Thread t0 = new Thread(t);Thread t1 = new Thread(t);Thread t2 = new Thread(t);t0.start();t1.start();t2.start();}}/** 通過線程休眠,出現安全問題* 解決安全問題,Java程序,提供技術,同步技術* 公式:* synchronized(任意對象){* 線程要操作的共享數據* }* 同步代碼塊*/public class Tickets implements Runnable{//定義出售的票源private int ticket = 100;private Object obj = new Object();public void run(){while(true){//線程共享數據,保證安全,加入同步代碼塊synchronized(obj){//對票數判斷,大于0,可以出售,變量--操作if( ticket > 0){try{Thread.sleep(10);}catch(Exception ex){}System.out.println(Thread.currentThread().getName()+" 出售第 "+ticket--);}}}}}05同步代碼塊的執行原理
A:同步代碼塊的執行原理同步代碼塊: 在代碼塊聲明上 加上synchronizedsynchronized (鎖對象) {可能會產生線程安全問題的代碼}同步代碼塊中的鎖對象可以是任意的對象;但多個線程時,要使用同一個鎖對象才能夠保證線程安全。06同步的上廁所原理
*A:同步的上廁所原理a:不使用同步:線程在執行的過程中會被打擾線程比喻成人線程執行代碼就是上一個廁所第一個人正在上廁所,上到一半,被另外一個人拉出來b:使用同步:線程比喻成人線程執行代碼就是上一個廁所鎖比喻成廁所門第一個人上廁所,會鎖門第二個人上廁所,看到門鎖上了,等待第一個人上完再去上廁所07同步方法
*A:同步方法:/** 多線程并發訪問同一個數據資源* 3個線程,對一個票資源,出售*/public class ThreadDemo {public static void main(String[] args) {//創建Runnable接口實現類對象Tickets t = new Tickets();//創建3個Thread類對象,傳遞Runnable接口實現類Thread t0 = new Thread(t);Thread t1 = new Thread(t);Thread t2 = new Thread(t);t0.start();t1.start();t2.start();}}*A:同步方法/** 采用同步方法形式,解決線程的安全問題* 好處: 代碼簡潔* 將線程共享數據,和同步,抽取到一個方法中* 在方法的聲明上,加入同步關鍵字* * 問題:* 同步方法有鎖嗎,肯定有,同步方法中的對象鎖,是本類對象引用 this* 如果方法是靜態的呢,同步有鎖嗎,絕對不是this* 鎖是本類自己.class 屬性* 靜態方法,同步鎖,是本類類名.class屬性*/public class Tickets implements Runnable{//定義出售的票源private int ticket = 100;public void run(){while(true){payTicket();}}public synchronized void payTicket(){ if( ticket > 0){try{Thread.sleep(10);}catch(Exception ex){}System.out.println(Thread.currentThread().getName()+" 出售第 "+ticket--);}}}08JDK1.5新特性Lock接口
*A:JDK1.5新特性Lock接口查閱API,查閱Lock接口描述,Lock 實現提供了比使用 synchronized 方法和語句可獲得的更廣泛的鎖定操作。? Lock接口中的常用方法void lock()void unlock()Lock提供了一個更加面對對象的鎖,在該鎖中提供了更多的操作鎖的功能。我們使用Lock接口,以及其中的lock()方法和unlock()方法替代同步,對電影院賣票案例中Ticket09Lock接口改進售票案例
*A:Lock接口改進售票案例/** 多線程并發訪問同一個數據資源* 3個線程,對一個票資源,出售*/public class ThreadDemo {public static void main(String[] args) {//創建Runnable接口實現類對象Tickets t = new Tickets();//創建3個Thread類對象,傳遞Runnable接口實現類Thread t0 = new Thread(t);Thread t1 = new Thread(t);Thread t2 = new Thread(t);t0.start();t1.start();t2.start();}}/** 使用JDK1.5 的接口Lock,替換同步代碼塊,實現線程的安全性* Lock接口方法:* lock() 獲取鎖* unlock()釋放鎖* 實現類ReentrantLock*/public class Tickets implements Runnable{//定義出售的票源private int ticket = 100;//在類的成員位置,創建Lock接口的實現類對象private Lock lock = new ReentrantLock();public void run(){while(true){//調用Lock接口方法lock獲取鎖lock.lock();//對票數判斷,大于0,可以出售,變量--操作if( ticket > 0){try{Thread.sleep(10);System.out.println(Thread.currentThread().getName()+" 出售第 "+ticket--);}catch(Exception ex){}finally{//釋放鎖,調用Lock接口方法unlocklock.unlock();}}}}}10線程的死鎖原理
*A:線程的死鎖原理 當線程任務中出現了多個同步(多個鎖) 時,如果同步中嵌套了其他的同步。這時容易引發一種現象:程序出現無限等待,這種現象我們稱為死鎖。這種情況能避免就 避免掉。synchronzied(A鎖){synchronized(B鎖){}}11線程的死鎖代碼實現
*A:線程的死鎖代碼實現public class DeadLock implements Runnable{private int i = 0;public void run(){while(true){if(i%2==0){//先進入A同步,再進入B同步synchronized(LockA.locka){System.out.println("if...locka");synchronized(LockB.lockb){System.out.println("if...lockb");}}}else{//先進入B同步,再進入A同步synchronized(LockB.lockb){System.out.println("else...lockb");synchronized(LockA.locka){System.out.println("else...locka");}}}i++;}}}public class DeadLockDemo {public static void main(String[] args) {DeadLock dead = new DeadLock();Thread t0 = new Thread(dead);Thread t1 = new Thread(dead);t0.start();t1.start();}}public class LockA {private LockA(){}public static final LockA locka = new LockA();}public class LockB {private LockB(){}public static final LockB lockb = new LockB();}### 12線程等待與喚醒案例介紹
*A:線程等待與喚醒案例介紹 等待喚醒機制所涉及到的方法:? wait() :等待,將正在執行的線程釋放其執行資格 和 執行權,并存儲到線程池中。? notify():喚醒,喚醒線程池中被wait()的線程,一次喚醒一個,而且是任意的。? notifyAll(): 喚醒全部:可以將線程池中的所有wait() 線程都喚醒。其實,所謂喚醒的意思就是讓 線程池中的線程具備執行資格。必須注意的是,這些方法都是在 同步中才有效。同時這些方法在使用時必須標明所屬鎖,這樣才可以明確出這些方法操作的到底是哪個鎖上的線程。13線程等待與喚醒案例資源類編寫
*A:線程等待與喚醒案例資源類編寫/** 定義資源類,有2個成員變量* name,sex* 同時有2個線程,對資源中的變量操作* 1個對name,age賦值* 2個對name,age做變量的輸出打印*/public class Resource {public String name;public String sex;}14線程等待與喚醒案例輸入和輸出線程
A:線程等待與喚醒案例輸入和輸出線程/** 輸入的線程,對資源對象Resource中成員變量賦值* 一次賦值 張三,男* 下一次賦值 lisi,nv*/public class Input implements Runnable {private Resource r=new Resource();public void run() {int i=0;while(true){if(i%2==0){r.name="張三";r.sex="男";}else{r.name="lisi";r.sex="女";}i++;}}}/** 輸出線程,對資源對象Resource中成員變量,輸出值*/public class Output implements Runnable {private Resource r=new Resource() ;public void run() {while(true){System.out.println(r.name+"..."+r.sex); }}}15線程等待與喚醒案例測試類
A:線程等待與喚醒案例測試類/** 開啟輸入線程和輸出線程,實現賦值和打印值*/public class ThreadDemo{public static void main(String[] args) {Resource r = new Resource();Input in = new Input();Output out = new Output();Thread tin = new Thread(in);Thread tout = new Thread(out);tin.start();tout.start();}}16線程等待與喚醒案例null值解決
A:線程等待與喚醒案例null值解決/** 輸入的線程,對資源對象Resource中成員變量賦值* 一次賦值 張三,男* 下一次賦值 lisi,nv*/public class Input implements Runnable {private Resource r;public Input(Resource r){this.r=r;}public void run() {int i=0;while(true){if(i%2==0){r.name="張三";r.sex="男";}else{r.name="lisi"r.sex="女"}i++;}}}/** 輸出線程,對資源對象Resource中成員變量,輸出值*/ public class Output implements Runnable {private Resource r;public Output(Resource r){this.r=r;} public void run() {while(true){System.out.println(r.name+"..."+r.sex); }}}}/** 開啟輸入線程和輸出線程,實現賦值和打印值*/public class ThreadDemo{public static void main(String[] args) {Resource r = new Resource();Input in = new Input(r);Output out = new Output(r);Thread tin = new Thread(in);Thread tout = new Thread(out);tin.start();tout.start();}}17線程等待與喚醒案例數據安全解決
A:線程等待與喚醒案例數據安全解決/** 輸入的線程,對資源對象Resource中成員變量賦值* 一次賦值 張三,男* 下一次賦值 lisi,nv*/public class Input implements Runnable {private Resource r;public Input(Resource r){this.r=r;}public void run() {int i=0;while(true){synchronized(r){if(i%2==0){r.name="張三";r.sex="男";}else{r.name="lisi"r.sex="女"}i++;}}}/** 輸出線程,對資源對象Resource中成員變量,輸出值*/ public class Output implements Runnable {private Resource r;public Output(Resource r){this.r=r;} public void run() {while(true){synchronized(r){System.out.println(r.name+"..."+r.sex); }}}}}/** 開啟輸入線程和輸出線程,實現賦值和打印值*/public class ThreadDemo{public static void main(String[] args) {Resource r = new Resource();Input in = new Input(r);Output out = new Output(r);Thread tin = new Thread(in);Thread tout = new Thread(out);tin.start();tout.start();}}18線程等待與喚醒案例通信的分析
*A:線程等待與喚醒案例通信的分析輸入:賦值后,執行方法wait()永遠等待輸出:變量值打印輸出,在輸出等待之前,喚醒輸入的notify(),自己在wait()永遠等待輸入:被喚醒后,重新對變量賦值,賦值后,必須喚醒輸出的線程notify(),自己的wait()19線程等待與喚醒案例的實現
*A 線程等待與喚醒案例的實現/** 定義資源類,有2個成員變量* name,sex* 同時有2個線程,對資源中的變量操作* 1個對name,age賦值* 2個對name,age做變量的輸出打印*/public class Resource {public String name;public String sex;public boolean flag = false;}/** 輸入的線程,對資源對象Resource中成員變量賦值* 一次賦值 張三,男* 下一次賦值 lisi,nv*/public class Input implements Runnable {private Resource r ;public Input(Resource r){this.r = r;}public void run() {int i = 0 ;while(true){synchronized(r){//標記是true,等待if(r.flag){try{r.wait();}catch(Exception ex){}}if(i%2==0){r.name = "張三";r.sex = "男";}else{r.name = "lisi";r.sex = "nv";}//將對方線程喚醒,標記改為truer.flag = true;r.notify();}i++;}}}/** 輸出線程,對資源對象Resource中成員變量,輸出值*/public class Output implements Runnable {private Resource r ;public Output(Resource r){this.r = r;}public void run() {while(true){synchronized(r){ //判斷標記,是false,等待if(!r.flag){try{r.wait();}catch(Exception ex){}}System.out.println(r.name+".."+r.sex);//標記改成false,喚醒對方線程r.flag = false;r.notify();}}}}/** 開啟輸入線程和輸出線程,實現賦值和打印值*/public class ThreadDemo{public static void main(String[] args) {Resource r = new Resource();Input in = new Input(r);Output out = new Output(r);Thread tin = new Thread(in);Thread tout = new Thread(out);tin.start();tout.start();}}作業測試
1、wait和sleep的區別
2、線程的生命周期(五中狀態的切換流程)
3、有一個抽獎池,該抽獎池中存放了獎勵的金額,該抽獎池用一個數組int[] arr = {10,5,20,50,100,200,500,800,2,80,300};
創建兩個抽獎箱(線程)設置線程名稱分別為“抽獎箱1”,“抽獎箱2”,隨機從arr數組中獲取獎項元素并打印在控制臺上,格式如下:
4、某公司組織年會,會議入場時有兩個入口,在入場時每位員工都能獲取一張雙色球彩票,假設公司有100個員工,利用多線程模擬年會入場過程,
并分別統計每個入口入場的人數,以及每個員工拿到的彩票的號碼。線程運行后打印格式如下: 編號為: 2 的員工 從后門 入場! 拿到的雙色球彩票號碼是: [17, 24, 29, 30, 31, 32, 07] 編號為: 1 的員工 從后門 入場! 拿到的雙色球彩票號碼是: [06, 11, 14, 22, 29, 32, 15] //..... 從后門入場的員工總共: 13 位員工 從前門入場的員工總共: 87 位員工轉載于:https://www.cnblogs.com/wanghui1234/p/9575392.html
總結
以上是生活随笔為你收集整理的27_多线程_第27天(线程安全、线程同步、等待唤醒机制、单例设计模式)_讲义...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python中的浅拷贝与深拷贝——cop
- 下一篇: Java模板引擎之freemarker简