摘要:線程操作共享數據的安全問題線程操作共享數據的安全問題如果有多個線程在同時運行,而這些線程可能會同時運行這段代碼。喚醒全部可以將線程池中的所有線程都喚醒。
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:同步代碼塊的執行原理
同步代碼塊: 在代碼塊聲明上 加上synchronized synchronized (鎖對象) { 可能會產生線程安全問題的代碼 } 同步代碼塊中的鎖對象可以是任意的對象;但多個線程時,要使用同一個鎖對象才能夠保證線程安全。
=======================第二節課開始=============================================
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接口方法unlock lock.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"; } //將對方線程喚醒,標記改為true r.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(); } }20eclipse問題
A:eclipse問題
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/67184.html
摘要:線程間通信其實就是多個線程操作同一個資源,但動作不同。同步前提是多線程。將該線程載入線程池,等待喚醒。該方法拋出異常,故需要配合使用隨機喚醒線程池中一線程。線程為了檢測死鎖,它需要遞進地檢測所有被請求的鎖。 線程間通信 其實就是多個線程操作同一個資源,但動作不同。示例:在某個數據庫中,Input輸入人的姓名,性別,Output輸出,兩個線程同時作用。思考:1.明確哪些代碼是多線程操作的...
摘要:多線程進程正在進行中的程序。所以容易出現線程安全問題。等待喚醒機制涉及的方法將同步中的線程處于凍結狀態。返回該線程的字符串表示形式,包括線程名稱優先級和線程組。暫停當前正在執行的線程對象,并執行其他線程。 多線程:進程:正在進行中的程序。其實進程就是一個應用程序運行時的內存分配空間。線程:其實就是進程中一個程序執行控制單元,一條執行路徑。進程負責的是應用程序的空間的標示。線程負責的是應...
摘要:例子先來看下面的示例來驗證下到底是不是線程安全的。上面的例子我們期望的結果應該是,但運行遍,你會發現總是不為,至少你現在知道了操作它不是線程安全的了。它的性能比較好也是因為避免了使線程進入內核態的阻塞狀態。 例子 先來看下面的示例來驗證下 i++ 到底是不是線程安全的。 1000個線程,每個線程對共享變量 count 進行 1000 次 ++ 操作。 showImg(https://s...
摘要:而且在大多數經典的多線程編程資料中,阻塞隊列都是其中非常重要的一個實踐案例。甚至可以說只有自己動手實現了一個阻塞隊列才能真正掌握多線程相關的。為什么會發生這種情況呢原因就是在我們實現的這個阻塞隊列中完全沒有線程同步機制,所以同時并發進行的個 阻塞隊列不止是一道熱門的面試題,同時也是許多并發處理模型的基礎,比如常用的線程池類ThreadPoolExecutor內部就使用了阻塞隊列來保存等...
摘要:本文探討并發中的其它問題線程安全可見性活躍性等等。當閉鎖到達結束狀態時,門打開并允許所有線程通過。在從返回時被叫醒時,線程被放入鎖池,與其他線程競爭重新獲得鎖。 本文探討Java并發中的其它問題:線程安全、可見性、活躍性等等。 在行文之前,我想先推薦以下兩份資料,質量很高:極客學院-Java并發編程讀書筆記-《Java并發編程實戰》 線程安全 《Java并發編程實戰》中提到了太多的術語...
閱讀 2235·2021-09-22 15:25
閱讀 3618·2019-08-30 12:48
閱讀 2207·2019-08-30 11:25
閱讀 2340·2019-08-30 11:05
閱讀 727·2019-08-29 17:28
閱讀 3287·2019-08-26 12:16
閱讀 2611·2019-08-26 11:31
閱讀 1707·2019-08-23 17:08