這篇文章主要講解了“什么是synchronized”,文中的講解內(nèi)容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“什么是synchronized”吧!
成都創(chuàng)新互聯(lián)公司服務(wù)項目包括黃梅網(wǎng)站建設(shè)、黃梅網(wǎng)站制作、黃梅網(wǎng)頁制作以及黃梅網(wǎng)絡(luò)營銷策劃等。多年來,我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢、行業(yè)經(jīng)驗、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,黃梅網(wǎng)站推廣取得了明顯的社會效益與經(jīng)濟效益。目前,我們服務(wù)的客戶以成都為中心已經(jīng)輻射到黃梅省份的部分城市,未來相信會繼續(xù)擴大服務(wù)區(qū)域并繼續(xù)獲得客戶的支持與信任!
上面也說了,synchronized可以寫在方法上,也可以寫在代碼塊上,只是有可能鎖的類型不同,如果寫在方法上,鎖的就是當前類的對象,在代碼塊上使用,可以指定鎖的對象。如果作用在靜態(tài)代碼塊上,鎖的就是指定的類的class對象了
synchronized鎖屬于全自動類型的,自動上鎖解鎖,而且在執(zhí)行代碼的過程中,如果拋異常了,synchronized也會自動釋放鎖
synchronized鎖是可重入鎖,就是當前線程調(diào)用A的方法,A方法中調(diào)用B方法,可以直接調(diào)用,不用競爭鎖。jvm這樣設(shè)計,也是為了防止死鎖的產(chǎn)生,所以,在這里你應(yīng)該也能明白了,為什么當前線程訪問A方法時,其他線程訪問其他方法時,不能讓其訪問的原因了?;蛘哌@樣說,T1線程訪問A方法時,T2線程也來訪問A方法,肯定不被允許的,這不不用多說,因為鎖的是一個對象,那個對象被T1線程鎖著呢,T2線程當然獲取不了鎖。那相同的,T2線程去訪問B方法時,B方法中鎖的不也是同一個對象嗎,也就是說T2線程還要去獲取T1線程在A方法中鎖定的對象的鎖。
threadlocal線程私有變量,舉個例子你就知道了:
public class ThreadLocalTest { class Person { String name = "zhangsan"; } @Test public void threadLocal1() { ThreadLocaltl = new ThreadLocal (); Person person = new Person(); tl.set(person); new Thread(new Runnable() { @Override public void run() { System.out.println("新啟線程"+tl.get()); } }).start(); System.out.println(tl.get()); try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
新啟的線程打印person為null,也就是說,通過threadlocal設(shè)置的對象,只能在當前線程中使用,其他線程獲取為空。
volatile關(guān)鍵字,請點擊跳轉(zhuǎn)
重點說下notify和wait,因為這里面的坑,稍不注意就掉進去了,之前寫過一篇,我再舉個生產(chǎn)者、消費者的例子: 需求:有2個生產(chǎn)者線程、10個消費者線程,如果容器滿了,則生產(chǎn)者暫停,如果容器空了,則消費者暫停
public class ProducerAndConsumer { //有2個生產(chǎn)者線程、10個消費者線程,如果容器滿了,則生產(chǎn)者暫停,如果容器空了,則消費者暫停 final private LinkedList list = new LinkedList(); final private int maxValue = 10; /** * 生產(chǎn)者,按照要求:當容器滿了,就停止。 */ public synchronized void producer(Object o) { /** * 最初的實現(xiàn)是用if,但是為什么又改成if而改成while呢:(這是一個坑,很容易掉里面) * 1.你想啊,如果此時,容器滿了,然后第一個線程到這后,判斷if邏輯,然后執(zhí)行wait方法進行等待,并【釋放當前對象鎖】 * 2.然后cpu調(diào)起哪個線程,是隨機選擇的,如果此時,又調(diào)起了一個生產(chǎn)者線程,那么也執(zhí)行到了這個wait方法。 * 3.目前已經(jīng)有兩個線程在wait這了,然后cpu執(zhí)行消費者線程消費了1個,現(xiàn)在容器中還有9個, * 然后消費者線程喚醒通過notifyall喚醒線程,喚醒了這兩個生產(chǎn)者線程,那么: * 3.1 首先第一個生產(chǎn)者線程開始執(zhí)行,從wait處開始往下執(zhí)行,添加元素,容器又滿了,釋放鎖 * 3.2 然后第二個生產(chǎn)者線程開始執(zhí)行,也是從wait處開始執(zhí)行,因為使用的不是while循環(huán),所以 * 會直接往下執(zhí)行,也就是添加元素,那么容器大小就不是10 個了。 * 4.所以,使用wait時的場景,99%都是與while循環(huán)配合使用 * 5.如果wait和notify不寫在synchronized鎖里面,會拋IllegalMonitorStateException異常,但是 * 為什么必須在synchronized鎖中呢,那么肯定會出現(xiàn)wait調(diào)用發(fā)生在調(diào)用notify之后的情況。[參考博客](https://www.cnblogs.com/set-cookie/p/8686218.html) */ // if(list.size()==maxValue) { while(list.size()==maxValue) { try { this.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } list.add(o); //容器中有東西了,喚醒等待的線程線程進行消費(喚醒的線程中包括生產(chǎn)者線程和消費者線程),其主要目的是消費者線程 this.notifyAll(); } /** * 消費者 */ public synchronized Object consumer() { while(list.size()==0) { try { this.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } //我拿走東西了,喚醒等待的線程進行生產(chǎn)(喚醒的線程中包括生產(chǎn)者線程和消費者線程),其主要目的是生產(chǎn)者線程 Object o = list.removeFirst(); this.notifyAll(); return o; } public static void main(String[] args) { ProducerAndConsumer pcTest = new ProducerAndConsumer(); //啟動消費者線程 for(int i=0;i<10;i++) { new Thread(()->{ for(int j=0;j<10;j++) { System.out.println(pcTest.consumer()+"aa"); } },"c"+i) .start(); } try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } //啟動生產(chǎn)者線程 for(int i=0;i<2;i++) { new Thread(()->{ for(int j=0;j<30;j++) { pcTest.producer(Thread.currentThread().getName()); } },"p"+i) .start(); } }
線程停止stop、interrupt方法, thread.stop(),是直接把你干掉了,沒有一點余地的直接kill掉,都不會進入catch中,所以不到萬不得已,不要用stop方法。 thread.interrupt()時,線程還是可以進下面catch中的代碼的。 但是這兩個方法都不被推薦,更理想的辦法是定義變量,:
public class ThreadStopByArgs { /** * 通過變量的形式,是線程進行停止 * */ public static void main(String[] args) { ThreadRunnerTest threadRunnerTest = new ThreadRunnerTest(); Thread thread = new Thread(threadRunnerTest); thread.start(); try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("stop"); threadRunnerTest.changeFlag(); } } class ThreadRunnerTest implements Runnable { private volatile boolean flag = true; public void run() { int i=0; while(flag) { //System.out.println(i++);測試多線程時,如果使用syso輸出,要小心使用,因為syso中有sync } } public void changeFlag(){ flag = false; } }
其他的方法,比如sleep、yield、join、stop、interrupt等方法,請您自行學習吧,沒啥好記得 鎖必須鎖的是同一個對象的基礎(chǔ)上的,如同:你衛(wèi)生間還能有多個門嗎?也就是說,訪問共享的資源時,只有一個門能讓你去訪問,這樣才能控制共享資源和線程的安全性。安全的意義并不只針對車禍那種類型的,只要預(yù)期結(jié)果被改變是因為在執(zhí)行過程中被其他因素干擾導(dǎo)致的,就屬于不安全。
感謝各位的閱讀,以上就是“什么是synchronized”的內(nèi)容了,經(jīng)過本文的學習后,相信大家對什么是synchronized這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識點的文章,歡迎關(guān)注!