摘要:線程操作共享數(shù)據(jù)的安全問題線程操作共享數(shù)據(jù)的安全問題如果有多個(gè)線程在同時(shí)運(yùn)行,而這些線程可能會同時(shí)運(yùn)行這段代碼。喚醒全部可以將線程池中的所有線程都喚醒。
01線程操作共享數(shù)據(jù)的安全問題
*A:線程操作共享數(shù)據(jù)的安全問題
如果有多個(gè)線程在同時(shí)運(yùn)行,而這些線程可能會同時(shí)運(yùn)行這段代碼。 程序每次運(yùn)行結(jié)果和單線程運(yùn)行的結(jié)果是一樣的,而且其他的變量的值也和預(yù)期的是一樣的,就是線程安全的。02售票的案例
*A:售票的案例
/* * 多線程并發(fā)訪問同一個(gè)數(shù)據(jù)資源 * 3個(gè)線程,對一個(gè)票資源,出售 */ public class ThreadDemo { public static void main(String[] args) { //創(chuàng)建Runnable接口實(shí)現(xiàn)類對象 Tickets t = new Tickets(); //創(chuàng)建3個(gè)Thread類對象,傳遞Runnable接口實(shí)現(xiàn)類 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線程安全問題引發(fā)
*A:線程安全問題引發(fā)
/* * 多線程并發(fā)訪問同一個(gè)數(shù)據(jù)資源 * 3個(gè)線程,對一個(gè)票資源,出售 */ public class ThreadDemo { public static void main(String[] args) { //創(chuàng)建Runnable接口實(shí)現(xiàn)類對象 Tickets t = new Tickets(); //創(chuàng)建3個(gè)Thread類對象,傳遞Runnable接口實(shí)現(xiàn)類 Thread t0 = new Thread(t); Thread t1 = new Thread(t); Thread t2 = new Thread(t); t0.start(); t1.start(); t2.start(); } } /* * 通過線程休眠,出現(xiàn)安全問題 */ public class Tickets implements Runnable{ //定義出售的票源 private int ticket = 100; private Object obj = new Object(); public void run(){ while(true){ //對票數(shù)判斷,大于0,可以出售,變量--操作 if( ticket > 0){ try{ Thread.sleep(10); //加了休眠讓其他線程有執(zhí)行機(jī)會 }catch(Exception ex){} System.out.println(Thread.currentThread().getName()+" 出售第 "+ticket--); } } } }04同步代碼塊解決線程安全問題
*A:同步代碼塊解決線程安全問題
*A:售票的案例 /* * 多線程并發(fā)訪問同一個(gè)數(shù)據(jù)資源 * 3個(gè)線程,對一個(gè)票資源,出售 */ public class ThreadDemo { public static void main(String[] args) { //創(chuàng)建Runnable接口實(shí)現(xiàn)類對象 Tickets t = new Tickets(); //創(chuàng)建3個(gè)Thread類對象,傳遞Runnable接口實(shí)現(xiàn)類 Thread t0 = new Thread(t); Thread t1 = new Thread(t); Thread t2 = new Thread(t); t0.start(); t1.start(); t2.start(); } } /* * 通過線程休眠,出現(xiàn)安全問題 * 解決安全問題,Java程序,提供技術(shù),同步技術(shù) * 公式: * synchronized(任意對象){ * 線程要操作的共享數(shù)據(jù) * } * 同步代碼塊 */ public class Tickets implements Runnable{ //定義出售的票源 private int ticket = 100; private Object obj = new Object(); public void run(){ while(true){ //線程共享數(shù)據(jù),保證安全,加入同步代碼塊 synchronized(obj){ //對票數(shù)判斷,大于0,可以出售,變量--操作 if( ticket > 0){ try{ Thread.sleep(10); }catch(Exception ex){} System.out.println(Thread.currentThread().getName()+" 出售第 "+ticket--); } } } } }05同步代碼塊的執(zhí)行原理
A:同步代碼塊的執(zhí)行原理
同步代碼塊: 在代碼塊聲明上 加上synchronized synchronized (鎖對象) { 可能會產(chǎn)生線程安全問題的代碼 } 同步代碼塊中的鎖對象可以是任意的對象;但多個(gè)線程時(shí),要使用同一個(gè)鎖對象才能夠保證線程安全。
=======================第二節(jié)課開始=============================================
06同步的上廁所原理*A:同步的上廁所原理
a:不使用同步:線程在執(zhí)行的過程中會被打擾 線程比喻成人 線程執(zhí)行代碼就是上一個(gè)廁所 第一個(gè)人正在上廁所,上到一半,被另外一個(gè)人拉出來 b:使用同步: 線程比喻成人 線程執(zhí)行代碼就是上一個(gè)廁所 鎖比喻成廁所門 第一個(gè)人上廁所,會鎖門 第二個(gè)人上廁所,看到門鎖上了,等待第一個(gè)人上完再去上廁所07同步方法
*A:同步方法:
/*
多線程并發(fā)訪問同一個(gè)數(shù)據(jù)資源
3個(gè)線程,對一個(gè)票資源,出售
*/
public class ThreadDemo {
public static void main(String[] args) { //創(chuàng)建Runnable接口實(shí)現(xiàn)類對象 Tickets t = new Tickets(); //創(chuàng)建3個(gè)Thread類對象,傳遞Runnable接口實(shí)現(xiàn)類 Thread t0 = new Thread(t); Thread t1 = new Thread(t); Thread t2 = new Thread(t); t0.start(); t1.start(); t2.start(); }
}
*A:同步方法
/* * 采用同步方法形式,解決線程的安全問題 * 好處: 代碼簡潔 * 將線程共享數(shù)據(jù),和同步,抽取到一個(gè)方法中 * 在方法的聲明上,加入同步關(guān)鍵字 * * 問題: * 同步方法有鎖嗎,肯定有,同步方法中的對象鎖,是本類對象引用 this * 如果方法是靜態(tài)的呢,同步有鎖嗎,絕對不是this * 鎖是本類自己.class 屬性 * 靜態(tài)方法,同步鎖,是本類類名.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 實(shí)現(xiàn)提供了比使用 synchronized 方法和語句可獲得的更廣泛的鎖定操作。 ? Lock接口中的常用方法 void lock() void unlock() Lock提供了一個(gè)更加面對對象的鎖,在該鎖中提供了更多的操作鎖的功能。 我們使用Lock接口,以及其中的lock()方法和unlock()方法替代同步,對電影院賣票案例中Ticket09Lock接口改進(jìn)售票案例
*A:Lock接口改進(jìn)售票案例
/* * 多線程并發(fā)訪問同一個(gè)數(shù)據(jù)資源 * 3個(gè)線程,對一個(gè)票資源,出售 */ public class ThreadDemo { public static void main(String[] args) { //創(chuàng)建Runnable接口實(shí)現(xiàn)類對象 Tickets t = new Tickets(); //創(chuàng)建3個(gè)Thread類對象,傳遞Runnable接口實(shí)現(xiàn)類 Thread t0 = new Thread(t); Thread t1 = new Thread(t); Thread t2 = new Thread(t); t0.start(); t1.start(); t2.start(); } } /* * 使用JDK1.5 的接口Lock,替換同步代碼塊,實(shí)現(xiàn)線程的安全性 * Lock接口方法: * lock() 獲取鎖 * unlock()釋放鎖 * 實(shí)現(xiàn)類ReentrantLock */ public class Tickets implements Runnable{ //定義出售的票源 private int ticket = 100; //在類的成員位置,創(chuàng)建Lock接口的實(shí)現(xiàn)類對象 private Lock lock = new ReentrantLock(); public void run(){ while(true){ //調(diào)用Lock接口方法lock獲取鎖 lock.lock(); //對票數(shù)判斷,大于0,可以出售,變量--操作 if( ticket > 0){ try{ Thread.sleep(10); System.out.println(Thread.currentThread().getName()+" 出售第 "+ticket--); }catch(Exception ex){ }finally{ //釋放鎖,調(diào)用Lock接口方法unlock lock.unlock(); } } } } }
=======================第三節(jié)課開始=============================================
10線程的死鎖原理*A:線程的死鎖原理
當(dāng)線程任務(wù)中出現(xiàn)了多個(gè)同步(多個(gè)鎖) 時(shí),如果同步中嵌套了其他的同步。這時(shí)容易引發(fā)一種現(xiàn)象:程序出現(xiàn)無限等待,這種現(xiàn)象我們稱為死鎖。這種情況能避免就避免掉。 synchronzied(A鎖){ synchronized(B鎖){ } }11線程的死鎖代碼實(shí)現(xiàn)
*A:線程的死鎖代碼實(shí)現(xiàn)
public class DeadLock implements Runnable{ private int i = 0; public void run(){ while(true){ if(i%2==0){ //先進(jìn)入A同步,再進(jìn)入B同步 synchronized(LockA.locka){ System.out.println("if...locka"); synchronized(LockB.lockb){ System.out.println("if...lockb"); } } }else{ //先進(jìn)入B同步,再進(jìn)入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:線程等待與喚醒案例介紹
等待喚醒機(jī)制所涉及到的方法: ? wait() :等待,將正在執(zhí)行的線程釋放其執(zhí)行資格 和 執(zhí)行權(quán),并存儲到線程池中。 ? notify():喚醒,喚醒線程池中被wait()的線程,一次喚醒一個(gè),而且是任意的。 ? notifyAll(): 喚醒全部:可以將線程池中的所有wait() 線程都喚醒。 其實(shí),所謂喚醒的意思就是讓 線程池中的線程具備執(zhí)行資格。必須注意的是,這些方法都是在 同步中才有效。同時(shí)這些方法在使用時(shí)必須標(biāo)明所屬鎖,這樣才可以明確出這些方法操作的到底是哪個(gè)鎖上的線程。13線程等待與喚醒案例資源類編寫
*A:線程等待與喚醒案例資源類編寫
/* * 定義資源類,有2個(gè)成員變量 * name,sex * 同時(shí)有2個(gè)線程,對資源中的變量操作 * 1個(gè)對name,age賦值 * 2個(gè)對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); } } }
=================================第四節(jié)課=========================================
15線程等待與喚醒案例測試類A:線程等待與喚醒案例測試類
/* * 開啟輸入線程和輸出線程,實(shí)現(xiàn)賦值和打印值 */ 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); } } } } /* * 開啟輸入線程和輸出線程,實(shí)現(xiàn)賦值和打印值 */ 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線程等待與喚醒案例數(shù)據(jù)安全解決
A:線程等待與喚醒案例數(shù)據(jù)安全解決 /* * 輸入的線程,對資源對象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); } } } } } /* * 開啟輸入線程和輸出線程,實(shí)現(xiàn)賦值和打印值 */ 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:線程等待與喚醒案例通信的分析 輸入:賦值后,執(zhí)行方法wait()永遠(yuǎn)等待 輸出:變量值打印輸出,在輸出等待之前,喚醒 輸入的notify(),自己在wait()永遠(yuǎn)等待 輸入:被喚醒后,重新對變量賦值,賦值后,必須喚醒輸出的線程notify(), 自己的wait()19線程等待與喚醒案例的實(shí)現(xiàn)
*A 線程等待與喚醒案例的實(shí)現(xiàn)
/* * 定義資源類,有2個(gè)成員變量 * name,sex * 同時(shí)有2個(gè)線程,對資源中的變量操作 * 1個(gè)對name,age賦值 * 2個(gè)對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){ //標(biāo)記是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"; } //將對方線程喚醒,標(biāo)記改為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){ //判斷標(biāo)記,是false,等待 if(!r.flag){ try{r.wait();}catch(Exception ex){} } System.out.println(r.name+".."+r.sex); //標(biāo)記改成false,喚醒對方線程 r.flag = false; r.notify(); } } } } /* * 開啟輸入線程和輸出線程,實(shí)現(xiàn)賦值和打印值 */ 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問題
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/67184.html
摘要:線程間通信其實(shí)就是多個(gè)線程操作同一個(gè)資源,但動作不同。同步前提是多線程。將該線程載入線程池,等待喚醒。該方法拋出異常,故需要配合使用隨機(jī)喚醒線程池中一線程。線程為了檢測死鎖,它需要遞進(jìn)地檢測所有被請求的鎖。 線程間通信 其實(shí)就是多個(gè)線程操作同一個(gè)資源,但動作不同。示例:在某個(gè)數(shù)據(jù)庫中,Input輸入人的姓名,性別,Output輸出,兩個(gè)線程同時(shí)作用。思考:1.明確哪些代碼是多線程操作的...
摘要:多線程進(jìn)程正在進(jìn)行中的程序。所以容易出現(xiàn)線程安全問題。等待喚醒機(jī)制涉及的方法將同步中的線程處于凍結(jié)狀態(tài)。返回該線程的字符串表示形式,包括線程名稱優(yōu)先級和線程組。暫停當(dāng)前正在執(zhí)行的線程對象,并執(zhí)行其他線程。 多線程:進(jìn)程:正在進(jìn)行中的程序。其實(shí)進(jìn)程就是一個(gè)應(yīng)用程序運(yùn)行時(shí)的內(nèi)存分配空間。線程:其實(shí)就是進(jìn)程中一個(gè)程序執(zhí)行控制單元,一條執(zhí)行路徑。進(jìn)程負(fù)責(zé)的是應(yīng)用程序的空間的標(biāo)示。線程負(fù)責(zé)的是應(yīng)...
摘要:例子先來看下面的示例來驗(yàn)證下到底是不是線程安全的。上面的例子我們期望的結(jié)果應(yīng)該是,但運(yùn)行遍,你會發(fā)現(xiàn)總是不為,至少你現(xiàn)在知道了操作它不是線程安全的了。它的性能比較好也是因?yàn)楸苊饬耸咕€程進(jìn)入內(nèi)核態(tài)的阻塞狀態(tài)。 例子 先來看下面的示例來驗(yàn)證下 i++ 到底是不是線程安全的。 1000個(gè)線程,每個(gè)線程對共享變量 count 進(jìn)行 1000 次 ++ 操作。 showImg(https://s...
摘要:而且在大多數(shù)經(jīng)典的多線程編程資料中,阻塞隊(duì)列都是其中非常重要的一個(gè)實(shí)踐案例。甚至可以說只有自己動手實(shí)現(xiàn)了一個(gè)阻塞隊(duì)列才能真正掌握多線程相關(guān)的。為什么會發(fā)生這種情況呢原因就是在我們實(shí)現(xiàn)的這個(gè)阻塞隊(duì)列中完全沒有線程同步機(jī)制,所以同時(shí)并發(fā)進(jìn)行的個(gè) 阻塞隊(duì)列不止是一道熱門的面試題,同時(shí)也是許多并發(fā)處理模型的基礎(chǔ),比如常用的線程池類ThreadPoolExecutor內(nèi)部就使用了阻塞隊(duì)列來保存等...
摘要:本文探討并發(fā)中的其它問題線程安全可見性活躍性等等。當(dāng)閉鎖到達(dá)結(jié)束狀態(tài)時(shí),門打開并允許所有線程通過。在從返回時(shí)被叫醒時(shí),線程被放入鎖池,與其他線程競爭重新獲得鎖。 本文探討Java并發(fā)中的其它問題:線程安全、可見性、活躍性等等。 在行文之前,我想先推薦以下兩份資料,質(zhì)量很高:極客學(xué)院-Java并發(fā)編程讀書筆記-《Java并發(fā)編程實(shí)戰(zhàn)》 線程安全 《Java并發(fā)編程實(shí)戰(zhàn)》中提到了太多的術(shù)語...
閱讀 2232·2021-09-22 15:25
閱讀 3617·2019-08-30 12:48
閱讀 2205·2019-08-30 11:25
閱讀 2338·2019-08-30 11:05
閱讀 725·2019-08-29 17:28
閱讀 3284·2019-08-26 12:16
閱讀 2608·2019-08-26 11:31
閱讀 1701·2019-08-23 17:08