摘要:非靜態方法以及方法內部的代碼塊持有的是同一個對象鎖,它們是同步執行的。可重入鎖使用時,當一個線程請求一個對象鎖時,再次請求該鎖是可以立即得到的。出現異常,會自動釋放鎖同步方法與同步代碼塊作用于整個方法,可能引起方法執行效率下降。
synchronize可以在多個線程操作同一個成員變量或者方法時,實現同步(或者互斥)的效果。
synchronized可以作用于方法,以及方法內部的代碼塊。
//1 synchronized void method(){} //2 static synchronized void method(){} //3 synchronized void method(){ synchronized(鎖對象){ } } //4 static synchronized void method(){ synchronized(鎖對象){ } }鎖對象
那么在上面的示例中,它們分別持有的鎖對象是誰?
synchronized作用于非靜態方法以及非靜態方法內部的代碼塊,持有的是當前類的對象的鎖,并且是同一個鎖。作用于靜態方法及其內部的代碼塊,持有的是當前類的Class對象的鎖,并且和非靜態方法不是同一個鎖。
通過代碼來驗證。
public class SynchronizedTest { private synchronized void test1(){ for (int x = 0; x < 5; x++) { System.out.println("test1---"+x); } } private void test2(){ synchronized(this) { for (int x = 0; x < 5; x++) { System.out.println("---test2---"+x); } } } private static synchronized void test3(){ for (int x = 0; x < 5; x++) { System.out.println("------test3---"+x); } } private static void test4(){ synchronized (SynchronizedTest.class){ for (int x = 0; x < 5; x++) { System.out.println("---------test4---"+x); } } } public static void main(String[] args) { SynchronizedTest synchronizedTest = new SynchronizedTest(); new Thread(new Runnable() { @Override public void run() { synchronizedTest.test1(); } }).start(); new Thread(new Runnable() { @Override public void run() { synchronizedTest.test2(); } }).start(); new Thread(new Runnable() { @Override public void run() { test3(); } }).start(); new Thread(new Runnable() { @Override public void run() { test4(); } }).start(); } }
執行結果
test1---0 ------test3---0 test1---1 ------test3---1 test1---2 test1---3 ------test3---2 test1---4 ------test3---3 ------test3---4 ---test2---0 ---test2---1 ---test2---2 ---test2---3 ---test2---4 ---------test4---0 ---------test4---1 ---------test4---2 ---------test4---3 ---------test4---4
test1和test2不會交叉執行,test3和test4也不會交叉執行。非靜態方法以及方法內部的代碼塊持有的是同一個對象鎖,它們是同步執行的。靜態方法和內部的代碼塊持有的是當前類的Class對象鎖,它們是同步執行的。而靜態方法和非靜態方法持有的不是同一個鎖,它們是異步的。
String作為鎖字符串常量作為鎖,會有什么結果?
final String a = "100"; final String b = "100"; new Thread(new Runnable() { @Override public void run() { synchronized (a){ while (true){ try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()); } } } },"thread-a").start(); new Thread(new Runnable() { @Override public void run() { synchronized (b){ while (true){ try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()); } } } },"thread-b").start();
這里字符串a和b雖然是兩個對象,但是聲明b時,會將字符串常量池中已存在的a的值直接賦給b。這樣a和b其實是一樣的。這樣線程thread-a和thread-b同時搶占同一個鎖,一旦一個線程搶到該鎖,另一個線程就再也獲取不到該鎖。
synchronized不具有繼承性自己覆蓋了父類被synchronized修飾的方法,子類方法如果需要同步性,也需要用synchronized修飾。
定義子類Sub繼承自SynchronizedTest
class Sub extends SynchronizedTest{ @Override public void test2() { //super.test2(); for (int x = 0; x < 15; x++) { try { Thread.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()); } } }
然后開啟兩個線程調用Sub的test2()方法。
final Sub sub = new Sub(); new Thread(new Runnable() { @Override public void run() { sub.test2(); } },"Sub---A").start(); new Thread(new Runnable() { @Override public void run() { sub.test2(); } },"Sub---B").start();
打印結果
Sub---A Sub---B Sub---A Sub---B Sub---A Sub---B Sub---A Sub---B
可見Sub的test2()方法并沒有同步性。也就是synchronized不能被繼承。
可重入鎖使用synchronized時,當一個線程請求一個對象鎖時,再次請求該鎖是可以立即得到的。
public class SynchronizedTest { private synchronized void test1(){ for (int x = 0; x < 5; x++) { System.out.println("test1---"+x); } test2(); } public void test2(){ synchronized(this) { for (int x = 0; x < 5; x++) { System.out.println("---test2---"+x); } } } public static void main(String[] args) { SynchronizedTest synchronizedTest = new SynchronizedTest(); new Thread(new Runnable() { @Override public void run() { synchronizedTest.test1(); } }).start(); } }
在方法test1()中調用方法test2(),并不需要等待鎖,而是立即獲取到鎖。
把子類Sub的test2()方法也改成synchronized修飾。并在其內部調用父類的test2()方法。能獲得鎖嗎?
class Sub extends SynchronizedTest{ @Override public synchronized void test2() { //調用父類的同步方法 super.test2(); for (int x = 0; x < 15; x++) { try { Thread.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()); } } }
打印結果
---test2---0 ---test2---1 ---test2---2 ---test2---3 ---test2---4 Sub---A Sub---A Sub---A Sub---A
可以看到父類方法執行完畢,子類的方法立即執行。可見,在子父類的繼承關系中,也支持可重入鎖這個特性。
出現異常,會自動釋放鎖 同步方法與同步代碼塊synchronized作用于整個方法,可能引起方法執行效率下降。建議將方法內部需要同步的代碼用synchronized修飾,也就是synchronized代碼塊。
多個同步鎖對象在一個類中假如有多個同步方法,它們之間并不需要互斥。那么使用同一個鎖,會大大降低效率。可以定義多個同步鎖對象。
Object obj1 = new Object(); Object obj2 = new Object(); public void method1(){ synchronized(obj1){ } } public void method2(){ synchronized(obj2){ } }
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/77669.html
摘要:轉載請備注地址多線程學習二將分為兩篇文章介紹同步方法另一篇介紹同步語句塊。如果兩個線程同時操作對象中的實例變量,則會出現非線程安全,解決辦法就是在方法前加上關鍵字即可。 轉載請備注地址: https://blog.csdn.net/qq_3433... Java多線程學習(二)將分為兩篇文章介紹synchronized同步方法另一篇介紹synchronized同步語句塊。系列文章傳送門...
摘要:關鍵字加到非靜態方法上持有的是對象鎖。線程和線程持有的鎖不一樣,所以和運行同步,但是和運行不同步。所以盡量不要使用而使用參考多線程編程核心技術并發編程的藝術如果你覺得博主的文章不錯,歡迎轉發點贊。 系列文章傳送門: Java多線程學習(一)Java多線程入門 Java多線程學習(二)synchronized關鍵字(1) java多線程學習(二)synchronized關鍵字(2) J...
摘要:本文對多線程基礎知識進行梳理,主要包括多線程的基本使用,對象及變量的并發訪問,線程間通信,的使用,定時器,單例模式,以及線程狀態與線程組。源碼采用構建,多線程這部分源碼位于模塊中。通知可能等待該對象的對象鎖的其他線程。 本文對多線程基礎知識進行梳理,主要包括多線程的基本使用,對象及變量的并發訪問,線程間通信,lock的使用,定時器,單例模式,以及線程狀態與線程組。 寫在前面 花了一周時...
摘要:一線程的基本概念單線程簡單的說,單線程就是進程中只有一個線程。多線程由一個以上線程組成的程序稱為多線程程序。當線程調用完方法進入后會自動釋放鎖,線程獲得鎖。 一、線程的基本概念 1.1 單線程 簡單的說,單線程就是進程中只有一個線程。單線程在程序執行時,所走的程序路徑按照連續順序排下來,前面的必須處理好,后面的才會執行。 Java示例: public class SingleThrea...
摘要:底層是是通過對象,對象有自己的對象頭,存儲了很多信息,其中一個信息標示是被哪個線程持有。當一個線程執行的代碼出現異常時,其所持有的鎖會自動釋放。 前言 回顧前面: 多線程三分鐘就可以入個門了! Thread源碼剖析 多線程基礎必要知識點!看了學習多線程事半功倍 只有光頭才能變強! 本文章主要講的是Java多線程加鎖機制,有兩種: Synchronized 顯式Lock 不得不嘮...
摘要:當一個線程持有重量級鎖時,另外一個線程就會被直接踢到同步隊列中等待。 java代碼先編譯成字節碼,字節碼最后編譯成cpu指令,因此Java的多線程實現最終依賴于jvm和cpu的實現 synchronized和volatile 我們先來討論一下volatile關鍵字的作用以及實現機制,每個線程看到的用volatile修飾的變量的值都是最新的,更深入的解釋就涉及到Java的內存模型了,我們...
閱讀 3296·2021-11-24 09:39
閱讀 2805·2021-10-12 10:20
閱讀 1908·2019-08-30 15:53
閱讀 3076·2019-08-30 14:14
閱讀 2600·2019-08-29 15:36
閱讀 1121·2019-08-29 14:11
閱讀 1956·2019-08-26 13:51
閱讀 3408·2019-08-26 13:23