小編給大家分享一下Synchronized怎么用,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
十載的尼開(kāi)遠(yuǎn)網(wǎng)站建設(shè)經(jīng)驗(yàn),針對(duì)設(shè)計(jì)、前端、開(kāi)發(fā)、售后、文案、推廣等六對(duì)一服務(wù),響應(yīng)快,48小時(shí)及時(shí)工作處理。營(yíng)銷型網(wǎng)站的優(yōu)勢(shì)是能夠根據(jù)用戶設(shè)備顯示端的尺寸不同,自動(dòng)調(diào)整尼開(kāi)遠(yuǎn)建站的顯示方式,使網(wǎng)站能夠適用不同顯示終端,在瀏覽器中調(diào)整網(wǎng)站的寬度,無(wú)論在任何一種瀏覽器上瀏覽網(wǎng)站,都能展現(xiàn)優(yōu)雅布局與設(shè)計(jì),從而大程度地提升瀏覽體驗(yàn)。創(chuàng)新互聯(lián)從事“尼開(kāi)遠(yuǎn)網(wǎng)站設(shè)計(jì)”,“尼開(kāi)遠(yuǎn)網(wǎng)站推廣”以來(lái),每個(gè)客戶項(xiàng)目都認(rèn)真落實(shí)執(zhí)行。
synchronized可以保證方法或者代碼塊在運(yùn)行時(shí),同一時(shí)刻只有一個(gè)方法可以進(jìn)入到臨界區(qū),同時(shí)它還可以保證共享變量的內(nèi)存可見(jiàn)性
Java中每一個(gè)對(duì)象都可以作為鎖,這是synchronized實(shí)現(xiàn)同步的基礎(chǔ):
1. 普通同步方法,鎖是當(dāng)前實(shí)例對(duì)象
2. 靜態(tài)同步方法,鎖是當(dāng)前類的class對(duì)象
3. 同步方法塊,鎖是括號(hào)里面的對(duì)象
synchronized 獲取的鎖,在方法拋出異常的時(shí)候會(huì)自動(dòng)解鎖
利用javap工具查看生成的class文件信息來(lái)分析Synchronize的實(shí)現(xiàn)
從上面可以看出,同步代碼塊是使用monitorenter和monitorexit指令實(shí)現(xiàn)的,同步方法(在這看不出來(lái)需要看JVM底層實(shí)現(xiàn))依靠的是方法修飾符上的ACC_SYNCHRONIZED實(shí)現(xiàn)。
同步代碼塊:monitorenter指令插入到同步代碼塊的開(kāi)始位置,monitorexit指令插入到同步代碼塊的結(jié)束位置,JVM需要保證每一個(gè)monitorenter都有一個(gè)monitorexit與之相對(duì)應(yīng)。任何對(duì)象都有一個(gè)monitor與之相關(guān)聯(lián),當(dāng)且一個(gè)monitor被持有之后,他將處于鎖定狀態(tài)。線程執(zhí)行到monitorenter指令時(shí),將會(huì)嘗試獲取對(duì)象所對(duì)應(yīng)的monitor所有權(quán),即嘗試獲取對(duì)象的鎖;
同步方法:synchronized方法則會(huì)被翻譯成普通的方法調(diào)用和返回指令如:invokevirtual、areturn指令,在VM字節(jié)碼層面并沒(méi)有任何特別的指令來(lái)實(shí)現(xiàn)被synchronized修飾的方法,而是在Class文件的方法表中將該方法的access_flags字段中的synchronized標(biāo)志位置1,表示該方法是同步方法并使用調(diào)用該方法的對(duì)象或該方法所屬的Class在JVM的內(nèi)部對(duì)象表示Klass做為鎖對(duì)象。
同步方法就是在方法前加關(guān)鍵字synchronized,然后被同步的方法一次只能有一個(gè)線程進(jìn)入,其他線程等待。
而同步塊則是在方法內(nèi)部使用大括號(hào)使得一個(gè)代碼塊得到同步。同步塊會(huì)有一個(gè)同步的”目標(biāo)“,使得同步塊更加靈活一些(同步塊可以通過(guò)”目標(biāo)“決定需要鎖定的對(duì)象)。一般情況下,如果此”目標(biāo)“為this,那么同步方法和同步塊沒(méi)有太大的區(qū)別。
synchronized 加到 static 方法前面是給class 加鎖,即類鎖;而synchronized 加到非靜態(tài)方法前面是給對(duì)象上鎖。這兩者的區(qū)別我用代碼來(lái)演示下:
對(duì)象鎖和類鎖是不同的鎖,所以多個(gè)線程同時(shí)執(zhí)行這2個(gè)不同鎖的方法時(shí),是異步的。
在Task2 中定義三個(gè)方法 doLongTimeTaskA和doLongTimeTaskB是類鎖,而doLongTimeTaskC是對(duì)象鎖。
public class Task2 {
public synchronized static void doLongTimeTaskA() {
System.out.println("name = " + Thread.currentThread().getName() + ", begain");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("name = " + Thread.currentThread().getName() + ", end");
}
public synchronized static void doLongTimeTaskB() {
System.out.println("name = " + Thread.currentThread().getName() + ", begain");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("name = " + Thread.currentThread().getName() + ", end");
}
public synchronized void doLongTimeTaskC() {
System.out.println("name = " + Thread.currentThread().getName() + ", begain");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("name = " + Thread.currentThread().getName() + ", end");
}
三個(gè)線程的代碼如下:
class ThreadA extends Thread{
private Task2 mTask2;
public ThreadA(Task2 tk){
mTask2 = tk;
}
public void run() {
mTask2.doLongTimeTaskA();
}
}
class ThreadB extends Thread{
private Task2 mTask2;
public ThreadB(Task2 tk){
mTask2 = tk;
}
public void run() {
mTask2.doLongTimeTaskB();
}
}
class ThreadC extends Thread{
private Task2 mTask2;
public ThreadC(Task2 tk){
mTask2 = tk;
}
public void run() {
mTask2.doLongTimeTaskC();
}
}
main函數(shù)中執(zhí)行代碼如下:
Task2 mTask2 = new Task2();
ThreadA ta = new ThreadA(mTask2);
ThreadB tb = new ThreadB(mTask2);
ThreadC tc = new ThreadC(mTask2);
ta.setName("A");
tb.setName("B");
tc.setName("C");
ta.start();
tb.start();
tc.start();
}
執(zhí)行的結(jié)果如下:
name = A, begain, time = 1487311199783
name = C, begain, time = 1487311199783
name = C, end, time = 1487311200784
name = A, end, time = 1487311200784
name = B, begain, time = 1487311200784
name = B, end, time = 1487311201784
可以看出由于 doLongTimeTaskA和doLongTimeTaskB都是類鎖,即同一個(gè)鎖,所以 A和B是按順序執(zhí)行,即同步的。而C是對(duì)象鎖,和A/B不是同一種鎖,所以C和A、B是 異步執(zhí)行的。(A、B、C代指上面的3中方法)。
我們知道對(duì)象鎖要想保持同步執(zhí)行,那么鎖住的必須是同一個(gè)對(duì)象。下面就修改下上面的來(lái)證明:
Task2.java不變,修改ThreadA 和 ThreadB 如下:
class ThreadA extends Thread{
private Task2 mTask2;
public ThreadA(Task2 tk){
mTask2 = tk;
}
public void run() {
mTask2.doLongTimeTaskC();
}
}
class ThreadB extends Thread{
private Task2 mTask2;
public ThreadB(Task2 tk){
mTask2 = tk;
}
public void run() {
mTask2.doLongTimeTaskC();
}
}
main方法如下:
Task2 mTaska = new Task2();
Task2 mTaskb = new Task2();
ThreadA ta = new ThreadA(mTaska );
ThreadB tb = new ThreadB(mTaskb );
ta.setName("A");
tb.setName("B");
ta.start();
tb.start();
結(jié)果如下:
name = A, begain, time = 1487311905775
name = B, begain, time = 1487311905775
name = B, end, time = 1487311906775
name = A, end, time = 1487311906775
從結(jié)果看來(lái),對(duì)象鎖鎖的對(duì)象不一樣,分別是mTaska , mTaskb,所以線程A和線程B調(diào)用 doLongTimeTaskC 是異步執(zhí)行的。
但是,類鎖可以對(duì)類的所有對(duì)象的實(shí)例起作用。只需修改ThradA
和 ThreadB,main 方法不做改變,修改如下:
class ThreadA extends Thread{
private Task2 mTask2;
public ThreadA(Task2 tk){
mTask2 = tk;
}
public void run() {
//mTask2.doLongTimeTaskC();
mTask2.doLongTimeTaskA();
}
}
class ThreadB extends Thread{
private Task2 mTask2;
public ThreadB(Task2 tk){
mTask2 = tk;
}
public void run() {
//mTask2.doLongTimeTaskC();
mTask2.doLongTimeTaskA();
}
}
結(jié)果如下:
name = A, begain, time = 1487312239674
name = A, end, time = 1487312240674
name = B, begain, time = 1487312240674
name = B, end, time = 1487312241674
可以看出 在線程A執(zhí)行完doLongTimeTaskA方法后,線程B才會(huì)獲得該類鎖接著去執(zhí)行doLongTimeTaskA。也就是說(shuō),類鎖對(duì)所有的該類對(duì)象都能起作用。
總結(jié):
1. 如果多線程同時(shí)訪問(wèn)同一類的 類鎖(synchronized 修飾的靜態(tài)方法)以及對(duì)象鎖(synchronized 修飾的非靜態(tài)方法)這兩個(gè)方法執(zhí)行是異步的,原因:類鎖和對(duì)象鎖是2中不同的鎖。
2. 類鎖對(duì)該類的所有對(duì)象都能起作用,而對(duì)象鎖不能。
之前談到過(guò),每個(gè)鎖關(guān)聯(lián)一個(gè)線程持有者和一個(gè)計(jì)數(shù)器。當(dāng)計(jì)數(shù)器為0時(shí)表示該鎖沒(méi)有被任何線程持有,那么任何線程都都可能獲得該鎖而調(diào)用相應(yīng)方法。當(dāng)一個(gè)線程請(qǐng)求成功后,JVM會(huì)記下持有鎖的線程,并將計(jì)數(shù)器計(jì)為1。此時(shí)其他線程請(qǐng)求該鎖,則必須等待。而該持有鎖的線程如果再次請(qǐng)求這個(gè)鎖,就可以再次拿到這個(gè)鎖,同時(shí)計(jì)數(shù)器會(huì)遞增。當(dāng)線程退出一個(gè)synchronized方法/塊時(shí),計(jì)數(shù)器會(huì)遞減,如果計(jì)數(shù)器為0則釋放該鎖。
以上是“Synchronized怎么用”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!