java并发编程实践学习---java的类锁和对象锁
最近在看Java Concurrent in Practice(java并發編程實踐),發現自己對java的線程、鎖等機制,理解很膚淺,學習的也不夠全面。打算借著這本書,全面的學習下JDK的并發包和一些線程相關的理論知識,填補自己的空白,也可以和大家交流,理解不正確的地方,歡迎指正。第一篇博客,先簡單的介紹下類鎖和對象鎖的概念,和關鍵字synchronized。
對象鎖:java的所有對象都含有1個互斥鎖,這個鎖由JVM自動獲取和釋放。線程進入synchronized方法的時候獲取該對象的鎖,當然如果已經有線程獲取了這個對象的鎖,那么當前線程會等待;synchronized方法正常返回或者拋異常而終止,JVM會自動釋放對象鎖。這里也體現了用synchronized來加鎖的1個好處,方法拋異常的時候,鎖仍然可以由JVM來自動釋放。
類鎖:對象鎖是用來控制實例方法之間的同步,類鎖是用來控制靜態方法(或靜態變量互斥體)之間的同步。其實類鎖只是一個概念上的東西,并不是真實存在的,它只是用來幫助我們理解鎖定實例方法和靜態方法的區別的。我們都知道,java類可能會有很多個對象,但是只有1個Class對象,也就是說類的不同實例之間共享該類的Class對象。Class對象其實也僅僅是1個java對象,只不過有點特殊而已。由于每個java對象都有1個互斥鎖,而類的靜態方法是需要Class對象。所以所謂的類鎖,不過是Class對象的鎖而已。獲取類的Class對象有好幾種,最簡單的就是MyClass.class的方式。
為什么需要加鎖呢?肯定是因為存在不同線程對共享對象的并發訪問,沒有數據共享就不需要鎖。
下面這個類,是我們使用java的synchronized方式進行控制的方法,會在我們后面的線程中調用。
?
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | package net.aty.lock.target; public class TargetMethod { ????// 對象鎖:形式1 ????public synchronized void objLockMethod1() ????{ ????????System.out.println("in...objLockMethod1"); ????????try ????????{ ????????????Thread.sleep(500); ????????} catch (InterruptedException e) ????????{ ????????????e.printStackTrace(); ????????} ????????System.out.println("out...objLockMethod1"); ????} ????// 對象鎖:形式2 ????public void objLockMethod2() ????{ ????????synchronized (this) ????????{ ????????????System.out.println("in...objLockMethod2"); ????????????try ????????????{ ????????????????Thread.sleep(500); ????????????} catch (InterruptedException e) ????????????{ ????????????????e.printStackTrace(); ????????????} ????????????System.out.println("out...objLockMethod2"); ????????} ????} ????// 類鎖:形式1 ????public static synchronized void classLock1() ????{ ????????System.out.println("classLock1------in"); ????????try ????????{ ????????????Thread.sleep(500); ????????} catch (InterruptedException e) ????????{ ????????????e.printStackTrace(); ????????} ????????System.out.println("classLock1------out"); ????} ????// 類鎖:形式2 ????public void classLock2() ????{ ????????synchronized (TargetMethod.class) ????????{ ????????????System.out.println("classLock2------in"); ????????????try ????????????{ ????????????????Thread.sleep(500); ????????????} catch (InterruptedException e) ????????????{ ????????????????e.printStackTrace(); ????????????} ????????????System.out.println("classLock2------out"); ????????} ????} } |
1、我們先來做第一個測試,該測試很簡單,說明:如果線程不存在數據共享,鎖就不會有效果,也就沒有必要加鎖。
?
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | package net.aty.lock.thread.first; import net.aty.lock.target.TargetMethod; public class DemoThread1 extends Thread { ????private TargetMethod target = null; ????public DemoThread1(TargetMethod target) ????{ ????????this.target = target; ????} ????@Override ????public void run() ????{ ????????target.objLockMethod1(); ????} } |
?
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | package net.aty.lock.thread.first; import net.aty.lock.target.TargetMethod; public class DemoThread2 extends Thread { ????private TargetMethod target = null; ????public DemoThread2(TargetMethod target) ????{ ????????this.target = target; ????} ????@Override ????public void run() ????{ ????????target.objLockMethod2(); ????} } |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | package net.aty.lock.thread.first; import net.aty.lock.target.TargetMethod; public class Test { ????public static void main(String[] args) throws Exception ????{ ????????test2(); ????} ????public static void test1() throws Exception ????{ ????????TargetMethod target1 = new TargetMethod(); ????????TargetMethod target2 = new TargetMethod(); ????????// 線程1運行后,睡眠500ms ????????Thread t1 = new DemoThread1(target1); ????????t1.start(); ????????// 主線程睡眠100ms后,恢復執行,此時線程1仍然處于睡眠狀態 ????????Thread.sleep(100); ????????System.out.println("main thread runnig...."); ????????// 線程2開始運行 ????????Thread t2 = new DemoThread2(target2); ????????t2.start(); ????} ????? ????public static void test2() throws Exception ????{ ????????TargetMethod shared = new TargetMethod(); ????????Thread t1 = new DemoThread1(shared); ????????t1.start(); ????????Thread.sleep(100); ????????System.out.println("main thread runnig...."); ????????Thread t2 = new DemoThread2(shared); ????????t2.start(); ????} } |
?
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | package net.aty.lock.thread.second; import net.aty.lock.target.TargetMethod; public class DemoThread3 extends Thread { ????public DemoThread3() ????{ ????} ????@Override ????public void run() ????{ ????????TargetMethod.classLock1(); ????} } |
?
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | package net.aty.lock.thread.second; import net.aty.lock.target.TargetMethod; public class DemoThread4 extends Thread { ????private TargetMethod target = null; ????public DemoThread4(TargetMethod target) ????{ ????????this.target = target; ????} ????@Override ????public void run() ????{ ????????target.classLock2(); ????} } |
?
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | package net.aty.lock.thread.second; import net.aty.lock.target.TargetMethod; public class Test { ????public static void main(String[] args) throws Exception ????{ ????????// 線程3運行后,睡眠500ms ????????Thread t1 = new DemoThread3(); ????????t1.start(); ????????// 主線程睡眠100ms后,恢復執行,此時線程1仍然處于睡眠狀態 ????????Thread.sleep(100); ????????System.out.println("main thread runnig...."); ????????// 線程4開始運行 ????????Thread t2 = new DemoThread4(new TargetMethod()); ????????t2.start(); ????} } |
執行結果如下:通過分析,可以知道的確實現了static方法之間的同步訪問
classLock1------in
main thread runnig....
classLock1------out
classLock2------in
classLock2------out
3、最后我們來測試下對象鎖和類鎖的區別和聯系。線程5會訪問同步的實例方法,線程6訪問同步的靜態方法。
?
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | package net.aty.lock.thread.third; import net.aty.lock.target.TargetMethod; public class DemoThread5 extends Thread { ????private TargetMethod target = null; ????public DemoThread5(TargetMethod target) ????{ ????????this.target = target; ????} ????@Override ????public void run() ????{ ????????target.objLockMethod1(); ????} } |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | package net.aty.lock.thread.third; import net.aty.lock.target.TargetMethod; public class DemoThread6 extends Thread { ????public DemoThread6() ????{ ????} ????@Override ????public void run() ????{ ????????TargetMethod.classLock1(); ????} } |
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | package net.aty.lock.thread.third; import net.aty.lock.target.TargetMethod; public class Test { ????public static void main(String[] args) throws Exception ????{ ????????test2(); ????} ????public static void test1() throws Exception ????{ ????????// 線程5開始運行 ????????Thread t1 = new DemoThread5(new TargetMethod()); ????????t1.start(); ????????// 主線程睡眠100ms后,恢復執行,此時線程1仍然處于睡眠狀態 ????????Thread.sleep(100); ????????System.out.println("main thread runnig...."); ????????// 線程6運行后,睡眠500ms ????????Thread t2 = new DemoThread6(); ????????t2.start(); ????} ????public static void test2() throws Exception ????{ ????????// 線程6開始運行 ????????Thread t2 = new DemoThread6(); ????????t2.start(); ????????// 主線程睡眠100ms后,恢復執行,此時線程1仍然處于睡眠狀態 ????????Thread.sleep(100); ????????System.out.println("main thread runnig...."); ????????// 線程5 ????????Thread t1 = new DemoThread5(new TargetMethod()); ????????t1.start(); ????} } |
執行結果如下:
classLock1------in
main thread runnig....
in...objLockMethod1
classLock1------out
out...objLockMethod1
可以看出,類鎖和對象鎖不是同1個東西,一個是類的Class對象的鎖,1個是類的實例的鎖。也就是說:1個線程訪問靜態synchronized的時候,允許另一個線程訪問對象的實例synchronized方法。反過來也是成立的,因為他們需要的鎖是不同的。
總結
以上是生活随笔為你收集整理的java并发编程实践学习---java的类锁和对象锁的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android深入透析之常用设计模式经验
- 下一篇: Android开发工具之Android