摘要:別的線程想要拿到鎖,就必須等待當前線程執行完成并釋放鎖,才能再次給對象加鎖,達到線程同步互斥作用。為了提升線程執行效率,就要最小化同步代碼塊,最小化鎖粒度。
在java中處理線程并發問題,可以簡單的加上synchronized,可以在方法或方法內的代碼塊添加,那現在的問題是,synchronized是鎖住了方法還是代碼塊還是實例對象?
加在方法上:
class Sync { public synchronized void test() { System.out.println("test開始.."); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("test結束.."); } } class MyThread extends Thread { public void run() { Sync sync = new Sync(); sync.test(); } } public class Main { public static void main(String[] args) { for (int i = 0; i < 3; i++) { Thread thread = new MyThread(); thread.start(); } } }
運行結果: test開始.. test開始.. test開始.. test結束.. test結束.. test結束
可以看到,上面啟了3個線程,每個線程實例化一個Sync并調用其方法,所以這里synchronized沒有作用,因為線程都加了各自的同步鎖,無互斥。
若把test方法上加上static,則運行結果如下:
test開始.. test結束.. test開始.. test結束.. test開始.. test結束
因為此時,3個線程的同步鎖是Sync類對象而不是類實例。
public static synchronized void test() { System.out.println("test開始.."); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("test結束.."); }
注:線程sleep時,并不會釋放鎖.
接下來,把synchronized加到this上,如下:
public void test() { synchronized(this) { System.out.println("test開始.."); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("test結束.."); } }
運行結果:test開始.. test開始.. test開始.. test結束.. test結束.. test結束
同樣的道理,這里的同步鎖是自各的對象實例,3個線程互不影響,沒有互斥作用
由此得知,synchronized在方法上鎖的是對象實例,在代碼塊里鎖的是括號里的對象。別的線程想要拿到鎖,就必須等待當前線程執行完成并釋放鎖,才能再次給對象加鎖,達到線程同步互斥作用。
為了提升線程執行效率,就要最小化同步代碼塊,最小化鎖粒度。
上面使用static實現了線程互斥,其實也可以用同一個對象來實現線程互斥,如下:
class MyThread extends Thread { private Sync sync; public MyThread(Sync sync) { this.sync = sync; } public void run() { sync.test(); } } public class Main { public static void main(String[] args) { Sync sync = new Sync(); for (int i = 0; i < 3; i++) { Thread thread = new MyThread(sync); thread.start(); } } }
運行結果:test開始.. test結束.. test開始.. test結束.. test開始.. test結束
可以看到,線程同步互斥了
更好的做法是,直接鎖住這個對象的class對象,與static相同,如下:
class Sync { public void test() { synchronized (Sync.class) { System.out.println("test開始.."); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("test結束.."); } } } class MyThread extends Thread { public void run() { Sync sync = new Sync(); sync.test(); } }
運行結果:test開始.. test結束.. test開始.. test結束.. test開始.. test結束
可以看到,線程仍然同步互斥
綜上,若需要同步鎖,盡量最小化同步塊。
學習交流,歡迎加群:64691032
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/76983.html
摘要:并發編程的挑戰并發編程的目的是為了讓程序運行的更快,但是,并不是啟動更多的線程就能讓程序最大限度的并發執行。的實現原理與應用在多線程并發編程中一直是元老級角色,很多人都會稱呼它為重量級鎖。 并發編程的挑戰 并發編程的目的是為了讓程序運行的更快,但是,并不是啟動更多的線程就能讓程序最大限度的并發執行。如果希望通過多線程執行任務讓程序運行的更快,會面臨非常多的挑戰:(1)上下文切換(2)死...
摘要:分布式鎖實現方式前言目前幾乎很多大型網站及應用都是分布式部署的,分布式場景中的數據一致性問題一直是一個比較重要的話題。基于數據庫實現分布式鎖基于緩存等實現分布式鎖基于實現分布式鎖。 前言 分布式鎖,是控制分布式系統之間同步訪問共享資源的一種方式 在分布式系統中,常常需要協調他們的動作。如果不同的系統或是同一個系統的不同主機之間共享了一個或一組資源,那么訪問這些資源的時候,往往需要互斥...
摘要:分布式鎖實現方式前言目前幾乎很多大型網站及應用都是分布式部署的,分布式場景中的數據一致性問題一直是一個比較重要的話題。基于數據庫實現分布式鎖基于緩存等實現分布式鎖基于實現分布式鎖。 前言 分布式鎖,是控制分布式系統之間同步訪問共享資源的一種方式 在分布式系統中,常常需要協調他們的動作。如果不同的系統或是同一個系統的不同主機之間共享了一個或一組資源,那么訪問這些資源的時候,往往需要互斥...
摘要:如問到是否使用某框架,實際是是問該框架的使用場景,有什么特點,和同類可框架對比一系列的問題。這兩個方向的區分點在于工作方向的側重點不同。 [TOC] 這是一份來自嗶哩嗶哩的Java面試Java面試 32個核心必考點完全解析(完) 課程預習 1.1 課程內容分為三個模塊 基礎模塊: 技術崗位與面試 計算機基礎 JVM原理 多線程 設計模式 數據結構與算法 應用模塊: 常用工具集 ...
摘要:而導致這個問題的原因是線程并行執行操作并不是原子的,存在線程安全問題。如果已經有線程持有了鎖,那這個線程會獨占鎖,直到鎖釋放完畢之前,其他線程都會被阻塞。當鎖處于重量級鎖狀態,其他線程嘗試獲取鎖時,都會被阻塞,也就是狀態。 1. 什么時候需要用SynchronizedSynchronized主要作用是在多個線程操作共享數據的時候,保證對共享數據訪問的線程安全性。比如兩個線程對于i這個共...
閱讀 2222·2021-11-18 10:02
閱讀 3480·2021-11-15 11:36
閱讀 1116·2019-08-30 14:03
閱讀 725·2019-08-30 11:08
閱讀 2761·2019-08-29 13:20
閱讀 3287·2019-08-29 12:34
閱讀 1375·2019-08-28 18:30
閱讀 1642·2019-08-26 13:34