多個線程調用同一個對象中的不同名稱的synchronized同步方法或synchronized(this)同步代碼塊時,調用的效果就是按順序執行,也就是同步的,阻塞的。
這說明synchronized同步方法或synchronized(this)同步代碼塊分別有兩種作用
(1)synchronized同步方法
1)對其他synchronized同步方法或synchronized(this)同步代碼塊調用呈阻塞狀態
2)同一時間只有一個線程可以執行synchronized同步方法中的代碼
(2)synchronized(this)同步代碼塊
1)對其他synchronized同步方法或synchronized(this)同步代碼塊調用呈阻塞狀態
2)同一時間只有一個線程可以執行synchronized(this)同步代碼塊中的代碼
Java還支持對“任意對象”作為“對象監視器”來實現同步的功能。這個“任意對象”大多數是實例變量及方法的參數,使用synchronized(非this對象)
synchronized(非this對象)格式的作用只有1中:synchronized(非this對象x)同步代碼塊
1)在多個線程持有“對象監視器”為同一個對象的前提下,同一時間只有一個線程可以執行synchronized(非this對象x)同步代碼塊中的代碼
2)當持有“對象監視器”為同一個對象的前提下,同一時間只有一個線程可以執行synchronized(非this對象x)同步代碼塊中的代碼。
package synBlockString; /** * Created by Administrator on 2017/1/19 0019. */ public class Service { private String usernameParam; private String passwordParam; private String anyString = new String(); public void setUsernamePassword(String username,String password){ try{ synchronized (anyString){ System.out.println("線程名稱為:"+Thread.currentThread().getName()+"在"+System.currentTimeMillis()+"進入同步"); usernameParam = username; Thread.sleep(2000); passwordParam = password; System.out.println("線程名稱為:"+Thread.currentThread().getName()+"在"+System.currentTimeMillis()+"離開同步"); } }catch(InterruptedException e){ e.printStackTrace(); } } }
package synBlockString; /** * Created by Administrator on 2017/1/19 0019. */ public class ThreadA extends Thread { private Service service; public ThreadA(Service service){ super(); this.service = service; } public void run(){ service.setUsernamePassword("a","aa"); } }
package synBlockString; /** * Created by Administrator on 2017/1/19 0019. */ public class ThreadB extends Thread { private Service service; public ThreadB(Service service){ super(); this.service = service; } public void run(){ service.setUsernamePassword("b","bb"); } }
package synBlockString; /** * Created by Administrator on 2017/1/19 0019. */ public class Run { public static void main(String [] args){ Service service = new Service(); ThreadA threadA = new ThreadA(service); threadA.setName("A"); threadA.start(); ThreadB threadB = new ThreadB(service); threadB.setName("B"); threadB.start(); threadB.start(); } }
線程名稱為:A在1484823811547進入同步
線程名稱為:A在1484823813559離開同步
線程名稱為:B在1484823813559進入同步
線程名稱為:B在1484823815573離開同步
如果修改service.java為
package synBlockString; /** * Created by Administrator on 2017/1/19 0019. */ public class Service { private String usernameParam; private String passwordParam; public void setUsernamePassword(String username,String password){ try{ String anyString = new String(); synchronized (anyString){ System.out.println("線程名稱為:"+Thread.currentThread().getName()+"在"+System.currentTimeMillis()+"進入同步"); usernameParam = username; Thread.sleep(2000); passwordParam = password; System.out.println("線程名稱為:"+Thread.currentThread().getName()+"在"+System.currentTimeMillis()+"離開同步"); } }catch(InterruptedException e){ e.printStackTrace(); } } }
線程名稱為:A在1484823870625進入同步
線程名稱為:B在1484823870625進入同步
線程名稱為:B在1484823872638離開同步
線程名稱為:A在1484823872638離開同步
所以,使用synchronized(非this對象)同步代碼塊格式進行同步操作時,對象監視器必須是同一個對象,如果不是同一個對象監視器,運行的結果就是異步調用了,就會交叉運行。
再看下一個示例:
package synBlockString2; /** * Created by Administrator on 2017/1/19 0019. */ public class Service { private String anyThing = new String(); public void a(){ try { synchronized (anyThing){ System.out.println("a begin"); Thread.sleep(2000); System.out.println("a end"); } } catch (InterruptedException e) { e.printStackTrace(); } } synchronized public void b(){ System.out.println(" b begin"); System.out.println(" b end"); } }
package synBlockString2; /** * Created by Administrator on 2017/1/19 0019. */ public class ThreadA extends Thread { private Service service; public ThreadA(Service service){ super(); this.service = service; } public void run(){ service.a(); } }
package synBlockString2; /** * Created by Administrator on 2017/1/19 0019. */ public class ThreadB extends Thread { private Service service; public ThreadB(Service service){ super(); this.service = service ; } public void run(){ service.b(); } }
package synBlockString2; /** * Created by Administrator on 2017/1/19 0019. */ public class Run { public static void main(String [] args){ Service service = new Service(); ThreadA threadA = new ThreadA(service); threadA.setName("A"); threadA.start(); ThreadB threadB = new ThreadB(service); threadB.setName("B"); threadB.start(); } }
運行結果:
a begin
b begin
b end
a end
由於對象監視器不同,所以運行結果就是異步的
同步代碼塊放在非同步synchronized方法中進行聲明,並不能保證調用方法的線程的執行同步/順序性,也就是線程調用方法的順序是無序的,雖然在同步塊中執行的順序是同步的,這樣就容易出現臟讀問題。