1. 程式人生 > >synchronized(this)、synchronized(class)與synchronized(Object)的區別

synchronized(this)、synchronized(class)與synchronized(Object)的區別

在多執行緒開發中,我們經常看到synchronized(this)、synchronized(*.class)與synchronized(任意物件)這幾種型別同步方法。但是是否知道這幾種寫法有什麼區別了?下面根據程式碼來分析:

synchronized程式碼塊間的同步性

package com.zwz.thread.demo1;

public class ObjectService {
	public void serviceMethodA(){
		try {
			synchronized (this) {
				System.out.println("A begin time="+System.currentTimeMillis());
				Thread.sleep(2000);
				System.out.println("A end   time="+System.currentTimeMillis());
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	public void serviceMethodB(){
		synchronized (this) {
			System.out.println("B begin time="+System.currentTimeMillis());
			System.out.println("B end   time="+System.currentTimeMillis());
		}
	}
}

package com.zwz.thread.demo1;

public class ThreadA extends Thread {
	private ObjectService objectService;
	public ThreadA(ObjectService objectService){
		super();
		this.objectService=objectService;
	}
	@Override
	public void run() {
		super.run();
		objectService.serviceMethodA();
	}
}

package com.zwz.thread.demo1;

public class ThreadB extends Thread {
	private ObjectService objectService;
	public ThreadB(ObjectService objectService){
		super();
		this.objectService=objectService;
	}
	@Override
	public void run() {
		super.run();
		objectService.serviceMethodB();
	}
}
package com.zwz.thread.demo1;

public class MainTest {
	public static void main(String[] args) {
		ObjectService service=new ObjectService();
		ThreadA a=new ThreadA(service);
		a.setName("a");
		a.start();
		ThreadB b=new ThreadB(service);
		b.setName("b");
		b.start();
	}
}

執行結果:


結論:

當一個執行緒訪問ObjectService的一個synchronized (this)同步程式碼塊時,其它執行緒對同一個ObjectService中其它的synchronized (this)同步程式碼塊的訪問將是堵塞,這說明synchronized (this)使用的物件監視器是一個。

驗證synchronized (this)程式碼塊是鎖定當前物件

package com.zwz.thread.demo2;

public class ObjectService {
	public void objectMethodA(){
		System.out.println("run----objectMethodA");
	}
	public void objectMethodB(){
		synchronized (this) {
			try {
				for (int i = 1; i <= 10; i++) {
					System.out.println("synchronized thread name:"+Thread.currentThread().getName()+"-->i="+i);
					Thread.sleep(1000);
				}
			} catch (InterruptedException e) {
					e.printStackTrace();
			}
		}
	}
}

package com.zwz.thread.demo2;

public class ThreadA extends Thread {
	private ObjectService objectService;

	public ThreadA(ObjectService objectService) {
		super();
		this.objectService = objectService;
	}
	@Override
	public void run() {
		super.run();
		objectService.objectMethodA();
	}
}

package com.zwz.thread.demo2;

public class ThreadB extends Thread {
	private ObjectService objectService;

	public ThreadB(ObjectService objectService) {
		super();
		this.objectService = objectService;
	}
	@Override
	public void run() {
		super.run();
		objectService.objectMethodB();
	}
}

package com.zwz.thread.demo2;

public class MainTest {
	public static void main(String[] args) throws InterruptedException {
		ObjectService service=new ObjectService();
		ThreadB b=new ThreadB(service);
		b.start();
		Thread.sleep(2000);
		ThreadA a=new ThreadA(service);
		a.start();
	}
}

執行結果:


可以看到objectMethodA方法非同步執行了,下面我們將objectMethodA()加上同步。

package com.zwz.thread.demo2;

public class ObjectService {
	public synchronized void objectMethodA(){
		System.out.println("run----objectMethodA");
	}
	public void objectMethodB(){
		synchronized (this) {
			try {
				for (int i = 1; i <= 10; i++) {
					System.out.println("synchronized thread name:"+Thread.currentThread().getName()+"-->i="+i);
					Thread.sleep(1000);
				}
			} catch (InterruptedException e) {
					e.printStackTrace();
			}
		}
	}
}

執行結果:


結論:

上面三個小例子我們可以知道,多個執行緒呼叫同一個物件中的不同名稱的synchronized同步方法或synchronized(this)同步程式碼塊時,是同步的。

1、synchronized同步方法

①對其它的synchronized同步方法或synchronized(this)同步程式碼塊呼叫是堵塞狀態;

②同一時間只有一個執行緒執行synchronized同步方法中的程式碼。

2、synchronized(this)同步程式碼塊

①對其它的synchronized同步方法或synchronized(this)同步程式碼塊呼叫是堵塞狀態;

②同一時間只有一個執行緒執行synchronized同步方法中的程式碼。


將任意物件作為物件監視器

package com.zwz.thread.demo3;

public class ObjectService {
	private String uname;
	private String pwd;
	String lock=new String();
	public void setUserNamePassWord(String userName,String passWord){
		try {
			synchronized (lock) {
				System.out.println("thread name="+Thread.currentThread().getName()
						+" 進入程式碼快:"+System.currentTimeMillis());
				uname=userName;
				Thread.sleep(3000);
				pwd=passWord;
				System.out.println("thread name="+Thread.currentThread().getName()
						+" 進入程式碼快:"+System.currentTimeMillis()+"入參uname:"+uname+"入參pwd:"+pwd);
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

package com.zwz.thread.demo3;

public class ThreadA extends Thread {
	private ObjectService objectService;

	public ThreadA(ObjectService objectService) {
		super();
		this.objectService = objectService;
	}
	@Override
	public void run() {
		objectService.setUserNamePassWord("a", "aa");
	}
}

package com.zwz.thread.demo3;

public class ThreadB extends Thread {
	private ObjectService objectService;

	public ThreadB(ObjectService objectService) {
		super();
		this.objectService = objectService;
	}
	@Override
	public void run() {
		objectService.setUserNamePassWord("b", "bb");
	}
}

package com.zwz.thread.demo3;

public class MainTest {
	public static void main(String[] args) {
		ObjectService service=new ObjectService();
		ThreadA a=new ThreadA(service);
		a.setName("A");
		a.start();
		ThreadB b=new ThreadB(service);
		b.setName("B");
		b.start();
	}
}

執行結果:


下面我把String lock=new String();放在方法中會有啥結果了:

package com.zwz.thread.demo3;

public class ObjectService {
	private String uname;
	private String pwd;
	public void setUserNamePassWord(String userName,String passWord){
		try {
			String lock=new String();
			synchronized (lock) {
				System.out.println("thread name="+Thread.currentThread().getName()
						+" 進入程式碼快:"+System.currentTimeMillis());
				uname=userName;
				Thread.sleep(3000);
				pwd=passWord;
				System.out.println("thread name="+Thread.currentThread().getName()
						+" 進入程式碼快:"+System.currentTimeMillis()+"入參uname:"+uname+"入參pwd:"+pwd);
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

執行結果:


結論:

多個執行緒持有物件監視器作為同一個物件的前提下,同一時間只有一個執行緒可以執行synchronized(任意自定義物件)同步程式碼快。

synchronized(任意自定義物件)與synchronized同步方法共用

package com.zwz.thread.demo4;

public class ObjectService {
	private String lock=new String();
	public void methodA(){
		try {
			synchronized (lock) {
				System.out.println("a begin");
				Thread.sleep(3000);
				System.out.println("a   end");
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	public synchronized void methodB(){
		System.out.println("b begin");
		System.out.println("b   end");
	}
}

package com.zwz.thread.demo4;

public class ThreadA extends Thread {
	private ObjectService objectService;

	public ThreadA(ObjectService objectService) {
		super();
		this.objectService = objectService;
	}
	@Override
	public void run() {
		objectService.methodA();
	}
}

package com.zwz.thread.demo4;

public class ThreadB extends Thread {
	private ObjectService objectService;

	public ThreadB(ObjectService objectService) {
		super();
		this.objectService = objectService;
	}
	@Override
	public void run() {
		objectService.methodB();
	}
}

package com.zwz.thread.demo4;

public class MainTest {
	public static void main(String[] args) {
		ObjectService service=new ObjectService();
		ThreadA a=new ThreadA(service);
		a.setName("A");
		a.start();
		ThreadB b=new ThreadB(service);
		b.setName("B");
		b.start();
	}
	
}

執行結果:


結論:

使用synchronized(任意自定義物件)進行同步操作,物件監視器必須是同一個物件。不過不是同一個,執行就是非同步執行了。

靜態同步synchronized方法與synchronized(*.class)程式碼塊

靜態同步synchronized方法

package com.zwz.thread.demo6;

public class ObjectService {
	public synchronized static void methodA(){
		try {
			System.out.println("static methodA begin 執行緒名稱:"+Thread.currentThread().getName()+" times:"+System.currentTimeMillis());
			Thread.sleep(3000);
			System.out.println("static methodA end   執行緒名稱:"+Thread.currentThread().getName()+" times:"+System.currentTimeMillis());
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	public synchronized static void methodB(){
		System.out.println("static methodB begin 執行緒名稱:"+Thread.currentThread().getName()+" times:"+System.currentTimeMillis());
		System.out.println("static methodB end   執行緒名稱:"+Thread.currentThread().getName()+" times:"+System.currentTimeMillis());
	}
}

package com.zwz.thread.demo6;

public class ThreadA extends Thread {

	@Override
	public void run() {
		ObjectService.methodA();
	}
}

package com.zwz.thread.demo6;

public class ThreadB extends Thread {
	@Override
	public void run() {
		ObjectService.methodB();
	}
}

package com.zwz.thread.demo6;

public class MainTest {
	public static void main(String[] args) {
		ThreadA a=new ThreadA();
		a.setName("A");
		a.start();
		ThreadB b=new ThreadB();
		b.setName("B");
		b.start();
	}
}

執行結果:
結論: synchronized應用在static方法上,那是對當前對應的*.Class進行持鎖。

synchronized(*.class)程式碼塊

package com.zwz.thread.demo7;

public class ObjectService {
	public void methodA(){
		try {
			synchronized (ObjectService.class) {
				System.out.println("methodA begin 執行緒名稱:"+Thread.currentThread().getName()+" times:"+System.currentTimeMillis());
				Thread.sleep(3000);
				System.out.println("methodA end   執行緒名稱:"+Thread.currentThread().getName()+" times:"+System.currentTimeMillis());
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	public void methodB(){
		synchronized (ObjectService.class) {
			System.out.println("methodB begin 執行緒名稱:"+Thread.currentThread().getName()+" times:"+System.currentTimeMillis());
			System.out.println("methodB end   執行緒名稱:"+Thread.currentThread().getName()+" times:"+System.currentTimeMillis());
		}
	}
}

package com.zwz.thread.demo7;

public class ThreadA extends Thread {
	private ObjectService objectService;

	public ThreadA(ObjectService objectService) {
		super();
		this.objectService = objectService;
	}
	@Override
	public void run() {
		objectService.methodA();
	}
}

package com.zwz.thread.demo7;

public class ThreadB extends Thread {
	private ObjectService objectService;

	public ThreadB(ObjectService objectService) {
		super();
		this.objectService = objectService;
	}
	@Override
	public void run() {
		objectService.methodB();
	}
}

package com.zwz.thread.demo7;

public class MainTest {
	public static void main(String[] args) {
		ObjectService service=new ObjectService();
		ThreadA a=new ThreadA(service);
		a.setName("A");
		a.start();
		ThreadB b=new ThreadB(service);
		b.setName("B");
		b.start();
	}
}

執行結果:
上面測試方法是共同物件,下面我們分別例項化一個物件:
package com.zwz.thread.demo7;

public class MainTest {
	public static void main(String[] args) {
		ObjectService service1=new ObjectService();
		ObjectService service2=new ObjectService();
		ThreadA a=new ThreadA(service1);
		a.setName("A");
		a.start();
		ThreadB b=new ThreadB(service2);
		b.setName("B");
		b.start();
	}
}

執行結果:
結論: 同步synchronized(*.class)程式碼塊的作用其實和synchronized static方法作用一樣。Class鎖對類的所有物件例項起作用。