官方介紹synchronized作用:
同步方法支持一種簡單的策略來防止線程干擾和內存一致性錯誤:如果一個對象對多個線程可見,則用改對象變量的所有讀取或寫入都是通過同步方法完成的。
一句話來說:
能夠保證一段時間內只有一個線程執行該段代碼,以達到併發安全的效果,是一種悲觀鎖。
看2段代碼:
public static void main(String[] args) {
for (int i = 0; i <2; i++) {
DoThreads dt = new DoThreads(0);
Thread dothread = new Thread(dt);
dothread.start();
}
}
public class DoThreads implements Runnable {
private static int money;
private static final Object o = new Object();
public DoThreads(int ages) {
super();
this.money = money;
}
@Override
public void run() {
testMethod();
}
public void testMethod(){
for (int i = 0; i < 1000; i++) {
try {
Thread.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
money=money+10;
}
System.out.println(Thread.currentThread().getName()+"開始"+"===金額"+money);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"結束"+"===金額"+money);
}
}
輸入結果爲:
Thread-0開始===金額19870
Thread-1開始===金額19920
Thread-0結束===金額19920
Thread-1結束===金額19920
說明2個線程工作的時候金額髮生了串號的錯誤。我們想要的結果是最後金額20000
這個時候我們的synchronized該上場了~
synchronized有2種用法:
1.對象鎖
包括方法鎖和同步代碼塊鎖
同步代碼塊鎖:
synchronized(this){
需要同步的代碼
}
Object o = new Object();
synchronized(o){
需要同步的代碼
}
方法鎖:
public synchronized void testMethod(){
}
2.類鎖
包括修飾靜態方法和鎖class對象或靜態object對象
修飾靜態方法:
public static synchronized void testMethod(){
需要鎖代碼
}
鎖class對象或靜態object對象
synchronized (DoThreads.class) {
}
static Object o = new Object();
synchronized(o){
需要同步的代碼
}
synchronized有2種用法介紹:
多線程執行同一任務對象,使用對象鎖和類鎖都能保證線程安全。
多線程執行不同任務對象,使用對象鎖不能保證線程安全,使用類鎖可以保證線程安全。
synchronize的性質
1 .可重入性
同一個線程的外層方法獲得鎖之後,內層方法可以直接再次獲取該鎖
優點 ps:避免死鎖 提高封裝性
2 .不可中斷性
一旦同一個鎖被別人獲得,只能等待別的線程釋放該鎖才能獲得,如果別人不釋放,只能永遠等下去。
synchronize缺陷
1.效率低
2.不夠靈活
3.無法知道是否成功獲得鎖
建議使用原則
能用工具包實現就不用synchronize;
能用synchronize實現就用synchronize;
最後再選擇lock鎖。
使用注意點:
鎖對象不能爲空,作用域不宜過大,避免死鎖