線程併發學習
線程併發學習—-核心概念(轉載)
線程併發學習—-線程阻塞(sleep、wait、notifyAll、notify、join)
線程併發學習—-線程阻塞(synchronized)
線程併發學習—-線程阻塞(lock)
線程併發學習—-Thread、Runnable、Callable
線程併發學習—-隊列(Queue)
spring學習—-線程池
java中一些鎖概念整理(轉載)
簡介
在併發編程中,我們需要處理兩個關鍵問題:線程之間如何通信及線程之間如何同步(這裏的線程是指併發執行的活動實體)。
通信是指線程之間以何種機制來交換信息。在命令式編程中,線程之間的通信機制有兩種:共享內存和消息傳遞。
Java的併發採用的是共享內存模型,Java線程之間的通信總是隱式進行,整個通信過程對程序員完全透明。在共享內存併發模型裏,同步是顯式進行的。程序員必須顯式指定某個方法或某段代碼需要在線程之間互斥執行。
線程安全是併發編程中的重要關注點,應該注意到的是,造成線程安全問題的主要誘因有兩點,
一是存在共享數據(也稱臨界資源),
二是存在多條線程共同操作共享數據。
在 Java 中synchronized 和 lock可以保證在同一個時刻,只有一個線程可以執行某個方法或者某個代碼塊
關鍵字 synchronized可以保證在同一個時刻,只有一個線程可以執行某個方法或者某個代碼塊(主要是對方法或者代碼塊中存在共享數據的操作),同時我們還應該注意到synchronized另外一個重要的作用,synchronized可保證一個線程的變化(主要是共享數據的變化)被其他線程所看到(保證可見性,完全可以替代Volatile功能),這點確實也是很重要的。
synchronized三種使用方式
- 修飾實例方法
- 修飾靜態方法
- 修飾同步代碼塊
修飾實例方法
實例代碼
public class NormalFunctionSyncDemo {
public static void main(String[] args) {
NormalFunctionSyncDemo normalFunctionSyncDemo = new NormalFunctionSyncDemo();
new Thread(new Runnable() {
@Override
public void run() {
normalFunctionSyncDemo.getA();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
NormalFunctionSyncDemo normalFunctionSyncDemo2 = new NormalFunctionSyncDemo();
normalFunctionSyncDemo2.getB();
}
}).start();
}
public synchronized void getA(){
System.out.println("get A.....");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("end A");
}
public synchronized void getB(){
System.out.println("get B.....");
System.out.println("end B");
}
}
結果分析
使用同一個實例對象,會阻塞
get A…..
end A
get B…..
end B
使用不同實例對象,不會阻塞
get A…..
get B…..
end B
end A
修飾靜態方法
代碼示例
public class StaticFunctionSyncDemo {
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
StaticFunctionSyncDemo.getA();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
StaticFunctionSyncDemo staticFunctionSyncDemo = new StaticFunctionSyncDemo();
staticFunctionSyncDemo.getB();
StaticFunctionSyncDemo.getA();
}
}).start();
}
public static synchronized void getA(){
System.out.println("get A.....");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("end A");
}
public synchronized void getB(){
System.out.println("get B.....");
System.out.println("end B");
}
}
結果分析
通類直接調用或創建新的示例調用getA方法都會阻塞,getB方法不會
get A…..
get B…..
end B
end A
get A…..
end A
修飾同步代碼塊
代碼示例
public class StaticBlockSyncDemo {
public static void main(String[] args) {
StaticBlockSyncDemo staticBlockSyncDemo = new StaticBlockSyncDemo();
new Thread(new Runnable() {
@Override
public void run() {
staticBlockSyncDemo.getA();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
StaticBlockSyncDemo staticBlockSyncDemo2 = new StaticBlockSyncDemo();
staticBlockSyncDemo.getB();
}
}).start();
}
public void getA(){
System.out.println("get A.....");
try {
synchronized (this) {
System.out.println("Method A execute");
Thread.sleep(3000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("end A");
}
public void getB(){
System.out.println("get B.....");
try {
synchronized (this) {
System.out.println("Method B execute");
Thread.sleep(3000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("end B");
}
}
結果分析
結果與實例方法類似,通過monitor監視器鎖實現
monitor監視器鎖
public void getA();
Code:
0: getstatic #11 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #12 // String get A.....
5: invokevirtual #13 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: aload_0
9: dup
10: astore_1
//通過javap命令可以看到獲取monitor鎖
11: monitorenter
12: getstatic #11 // Field java/lang/System.out:Ljava/io/PrintStream;
15: ldc #14 // String Method A execute
17: invokevirtual #13 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
20: ldc2_w #15 // long 3000l
23: invokestatic #17 // Method java/lang/Thread.sleep:(J)V
26: aload_1
27: monitorexit
參考資料
http://blog.csdn.net/javazejian/article/details/72828483?locationNum=5&fps=1
http://www.cnblogs.com/paddix/p/5374810.html