注:java
當一個線程執行的代碼出現異常時,其所持有的鎖會自動釋放併發
同步不具備繼承性異步
不在synchronized塊中就是一部執行,在synchronized中就是同步執行ide
和synchronized方法同樣,synchronized(this)代碼塊也是鎖定當前對象的學習
1. 同步的弊端this
public class CommonUtils { public static long startTime1; public static long endTime1; public static long startTime2; public static long endTime2; }
public class DemeritOfSynchronized { private String username; private String password; public synchronized void test() { try{ System.out.println("begin the test"); Thread.sleep(3000); username = "username is " + Thread.currentThread().getName(); password = "password is " + System.currentTimeMillis(); System.out.println(username); System.out.println(password); System.out.println("end the test"); }catch (Exception e){ e.printStackTrace(); } } }
public class FirstThread extends Thread { private DemeritOfSynchronized demeritOfSynchronized; public FirstThread(DemeritOfSynchronized demeritOfSynchronized) { super(); this.demeritOfSynchronized = demeritOfSynchronized; } @Override public void run() { super.run(); CommonUtils.startTime1 = System.currentTimeMillis(); demeritOfSynchronized.test(); CommonUtils.endTime1 = System.currentTimeMillis(); } }
public class SecondThread extends Thread { private DemeritOfSynchronized demeritOfSynchronized; public SecondThread(DemeritOfSynchronized demeritOfSynchronized) { super(); this.demeritOfSynchronized = demeritOfSynchronized; } @Override public void run() { super.run(); CommonUtils.startTime2 = System.currentTimeMillis(); demeritOfSynchronized.test(); CommonUtils.endTime2 = System.currentTimeMillis(); } }
public class Run { public static void main(String[] args) { DemeritOfSynchronized demeritOfSynchronized = new DemeritOfSynchronized(); FirstThread firstThread = new FirstThread(demeritOfSynchronized); firstThread.start(); SecondThread secondThread = new SecondThread(demeritOfSynchronized); secondThread.start(); try { Thread.sleep(10000); } catch (Exception e) { e.printStackTrace(); } long beginTime = CommonUtils.startTime1; if (CommonUtils.startTime2 < CommonUtils.startTime1) { beginTime = CommonUtils.startTime2; } long endTime = CommonUtils.endTime2; if (CommonUtils.endTime1 > CommonUtils.endTime2) { endTime = CommonUtils.endTime1; } System.out.println("spend time " + (endTime - beginTime) / 1000); } }
運行結果:線程
2. 同步代碼塊的使用對象
當兩個併發線程訪問同一個對象的object中的synchronized(this)同步代碼塊時,一段時間內只能有一個線程被執行名一個線程必須等待當前線程執行完這個代碼塊以後才能執行改代碼塊.繼承
public class ServiceMethod { public void ServiceMethod() { try { synchronized (this){ System.out.println("begin time = " + System.currentTimeMillis()); Thread.sleep(2222); System.out.println("end time = " + System.currentTimeMillis()); } }catch (Exception e){ e.printStackTrace(); } } }
public class FirstThread extends Thread { private ServiceMethod serviceMethod; public FirstThread(ServiceMethod serviceMethod){ super(); this.serviceMethod = serviceMethod; } @Override public void run(){ super.run(); serviceMethod.ServiceMethod(); } }
public class SecondThread extends Thread { private ServiceMethod serviceMethod; public SecondThread(ServiceMethod serviceMethod){ super(); this.serviceMethod = serviceMethod; } @Override public void run(){ super.run(); serviceMethod.ServiceMethod(); } }
public class Run { public static void main(String[] args){ ServiceMethod serviceMethod = new ServiceMethod(); FirstThread firstThread = new FirstThread(serviceMethod); firstThread.start(); SecondThread secondThread = new SecondThread(serviceMethod); secondThread.start(); } }
運行結果:get
3.用同步代碼塊解決同步方法的弊端
將1中的DemeritOfSynchronized方法代碼修改成
public class DemeritOfSynchronized { private String username; private String password; public void test() { try{ System.out.println("begin the test"); Thread.sleep(3000); synchronized (this){ username = "username is " + Thread.currentThread().getName(); password = "password is " + System.currentTimeMillis(); } System.out.println(username); System.out.println(password); System.out.println("end the test"); }catch (Exception e){ e.printStackTrace(); } } }
運行結果:
4.synchronized代碼塊之間的同步性
在使用synchronized(this)代碼塊時須要注意的是,當一個線程訪問object的一個synchronized(this)同步代碼塊時,其餘線程對同一個object對象中全部其餘synchronized(this)同步代碼塊的訪問將被阻塞,這說明synchronized使用的對象監視器是一個.
public class SynchronizedCodes { public void SynchronizedCodes() { try { synchronized (this) { System.out.println("A begin time = " + System.currentTimeMillis()); Thread.sleep(2000); System.out.println("A end time = " + System.currentTimeMillis()); } } catch (Exception e) { e.printStackTrace(); } } public void SynchronizedCodesB() { synchronized (this) { System.out.println("B begin time = " + System.currentTimeMillis()); System.out.println("B end time = " + System.currentTimeMillis()); } } }
public class FirstThread extends Thread{ SynchronizedCodes synchronizedCodes = new SynchronizedCodes(); public FirstThread(SynchronizedCodes synchronizedCodes){ super(); this.synchronizedCodes = synchronizedCodes; } @Override public void run(){ super.run(); synchronizedCodes.SynchronizedCodes(); } }
public class SecondThread extends Thread{ SynchronizedCodes synchronizedCodes = new SynchronizedCodes(); public SecondThread(SynchronizedCodes synchronizedCodes){ super(); this.synchronizedCodes = synchronizedCodes; } @Override public void run(){ super.run(); synchronizedCodes.SynchronizedCodesB(); } }
public class Run { public static void main(String[] args){ SynchronizedCodes synchronizedCodes = new SynchronizedCodes(); FirstThread firstThread = new FirstThread(synchronizedCodes); firstThread.start(); SecondThread secondThread = new SecondThread(synchronizedCodes); secondThread.start(); } }
運行結果:
5. 將任意對象做爲對象監視器
多個線程調用同一個對象中的不一樣名稱的synchronized同步方法或synchronized(this)同步代碼塊時,調用的效果就是按順序執行,也就是同步的,阻塞的.
1) synchronized同步方法
①對其餘synchronized同步方法或synchronized(this)同步代碼塊調用呈阻塞狀態.
②同一時間只有一個線程能夠執行synchronized同步方法中的代碼.
2) synchronized(this)同步代碼塊
①對其餘synchronized同步方法或synchronized(this)同步代碼塊調用呈阻塞狀態.
②同一時間只有一個線程能夠執行synchronized(this)同步代碼塊中的代碼
在前面的學習中,使用synchronized(this)格式來同步代碼塊,其實java還支持對任意對象做爲對象監視器來實現同步的功能,這個任意對象大多數是實例變量及方法的參數,使用格式爲synchronized(非this對象).
根據前面對synchronized(this)同步代碼塊的做用總結可知,synchronized(非this對象)格式的做用只有1種:synchronized(非this對象x同步代碼塊).
1)在多個線程持用對象監視器爲同一個對象的前提下,同一時間只有一個線程能夠執行synchronized(非this對象x)同步代碼塊中的代碼.
2)當持有對象監視器爲同一個對象的前提下,同一時間只有一個線程能夠執行synchronized(非this對象x)同步代碼塊中的代碼.
public class SynchronizedByAnyString { private String username; private String password; private String anyString = new String(); public void setUsernamAndPassword(String user, String pswd) { try { synchronized (anyString) { System.out.println("The Thread is " + Thread.currentThread().getName() + " enter time is " + System.currentTimeMillis()); username = user; Thread.sleep(2000); password = pswd; System.out.println("The Thread is " + Thread.currentThread().getName() + " leave time is " + System.currentTimeMillis()); } } catch (Exception e) { e.printStackTrace(); } } }
public class FirstThread extends Thread{ SynchronizedByAnyString synchronizedByAnyString = new SynchronizedByAnyString(); public FirstThread(SynchronizedByAnyString synchronizedByAnyString){ super(); this.synchronizedByAnyString = synchronizedByAnyString; } @Override public void run(){ super.run(); synchronizedByAnyString.setUsernamAndPassword("scymore","scymorePassword"); } }
public class SecondThread extends Thread{ SynchronizedByAnyString synchronizedByAnyString = new SynchronizedByAnyString(); public SecondThread(SynchronizedByAnyString synchronizedByAnyString){ super(); this.synchronizedByAnyString = synchronizedByAnyString; } @Override public void run(){ super.run(); synchronizedByAnyString.setUsernamAndPassword("b","bbbb"); } }
public class Run { public static void main(String[] args){ SynchronizedByAnyString synchronizedByAnyString = new SynchronizedByAnyString(); FirstThread firstThread = new FirstThread(synchronizedByAnyString); firstThread.setName("firstThread"); firstThread.start(); SecondThread secondThread = new SecondThread(synchronizedByAnyString); secondThread.setName("secondThread"); secondThread.start(); } }
運行結果:
鎖非this對象具備必定的優勢:若是在一個類中有不少個synchronized方法,這是雖然能實現同步,但會受到阻塞,因此影響運行效率;但若是使用同步代碼塊鎖非this對象,則synchronized(非this)代碼塊中的程序與同步方法是異步的,不與其餘鎖this同步方法爭搶this鎖,則可大大提升運行效率.