使用 Synchronized 關鍵字來解決并發(fā)問題是最簡單的一種方式凫碌,我們只需要使用它修飾需要被并發(fā)處理的代碼塊扑毡、方法或字段屬性,虛擬機自動為它加鎖和釋放鎖盛险,并將不能獲得鎖的線程阻塞在相應的阻塞隊列上瞄摊。
下面通過幾個例子看下Synchronized 的用法
1、不加鎖控制
public class TestSynchronized {
public void print1() {
int i = 5;
while (i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
sleep(500);
}
}
public void print2() {
int i = 5;
while (i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
sleep(500);
}
}
private void sleep(int time) {
try {
Thread.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
TestSynchronized obj = new TestSynchronized();
Thread threadA = new Thread(new Runnable() {
@Override
public void run() {
obj.print1();
}
});
Thread threadB = new Thread(new Runnable() {
@Override
public void run() {
obj.print2();
}
});
threadA.start();
threadB.start();
}
}
上述代碼沒有通過Synchronized 控制苦掘,print1和print2方法分別在不同的線程中執(zhí)行换帜,可以想象結果應該是交叉輸出的
Thread-1 : 4
Thread-0 : 4
Thread-1 : 3
Thread-0 : 3
Thread-0 : 2
Thread-1 : 2
Thread-0 : 1
Thread-1 : 1
Thread-0 : 0
Thread-1 : 0
2、使用Synchronized
public synchronized void print1() {
int i = 5;
while (i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
sleep(500);
}
}
public synchronized void print2() {
int i = 5;
while (i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
sleep(500);
}
}
可以看出結果是依次打印的
Thread-0 : 4
Thread-0 : 3
Thread-0 : 2
Thread-0 : 1
Thread-0 : 0
Thread-1 : 4
Thread-1 : 3
Thread-1 : 2
Thread-1 : 1
Thread-1 : 0
print1()和print2()前面的Synchronized獲取的是同一個鎖鹤啡,都是當前對象實例的內置鎖惯驼,所以當有一個線程獲取了這個鎖之后,其他需要調用帶Synchronized方法的線程只能阻塞递瑰。
3祟牲、Synchronized修飾代碼塊
public void print1() {
synchronized (this) {
int i = 5;
while (i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
sleep(500);
}
}
}
public synchronized void print2() {
int i = 5;
while (i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
sleep(500);
}
}
結果一樣是依次輸出
Thread-1 : 4
Thread-1 : 3
Thread-1 : 2
Thread-1 : 1
Thread-1 : 0
Thread-0 : 4
Thread-0 : 3
Thread-0 : 2
Thread-0 : 1
Thread-0 : 0
代碼塊前的synchronized 和print2()前的synchronized獲取的都是同一個對象的內置鎖。
4抖部、引入static
public void print1() {
synchronized (this) {
int i = 5;
while (i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
sleep(500);
}
}
}
public static synchronized void print2() {
int i = 5;
while (i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
sleep(500);
}
}
結果又變成交叉的了
Thread-1 : 4
Thread-0 : 4
Thread-1 : 3
Thread-0 : 3
Thread-1 : 2
Thread-0 : 2
Thread-0 : 1
Thread-1 : 1
Thread-0 : 0
Thread-1 : 0
代碼塊前的synchronized獲取的是當前對象的內置鎖说贝, print2是static獲取的是類對象的內置鎖,兩個鎖之前不存在競爭關系慎颗,同一個線程可以同時擁有兩把鎖乡恕。
原理解析
synchronized的使用需要借助java的內置鎖言询,首先看下內置鎖是什么
java的內置鎖:每個java對象都可以用做一個實現(xiàn)同步的鎖,這些鎖稱為內置鎖几颜。線程進入同步代碼塊或方法的時候會自動獲得該鎖倍试,在退出同步代碼塊或方法時會釋放該鎖。獲得內置鎖的唯一途徑就是進入這個鎖的保護的同步代碼塊或方法蛋哭。
示例2和3都是依次輸出的县习,說明兩個線程獲取的都是同一個對象鎖。
示例4 synchronized同時修飾靜態(tài)方法和實例方法谆趾,但是運行結果是交替進行的躁愿,這證明了類鎖和對象鎖是兩個不一樣的鎖,控制著不同的區(qū)域沪蓬,它們是互不干擾的彤钟。同樣,線程獲得對象鎖的同時跷叉,也可以獲得該類鎖逸雹,即同時獲得兩個鎖,這是允許的云挟。
引自:
https://www.cnblogs.com/edwardru/articles/6030686.html
synchronized是可重入的
引自:
https://blog.csdn.net/u012545728/article/details/80843595