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鎖對類的所有物件例項起作用。