[Java] 锁机制之synchronized

在处理多线程同步问题的时候,方法之一就是使用锁机制来同步多个线程在同一时刻对同一资源访问。在这里需要强调的是这两个“同一”的概念,第一是在同一时刻,如果每个线程都在不同的时刻进行访问,并且访问的时长也不重叠,就不需要进行同步;第二是同一资源,如果每个线程都访问不同的资源,那就更不需要同步了。同一时刻和我们日常生活中的时刻可能不太一样,不过可以这样去帮助理解。同一资源的界定要根据实际情况来定,在处理时需要谨慎。在java里面支持锁的使用的关键字是synchronized,根据同步级别的不同,它可以应用在方法上或代码块上,就是所谓的同步方法和同步块。根据同步的范围不同,它可以应用到一个类的实例上或一个类自己上,这就是实例的同步和类的同步。以上四种是比较常用的情况,而且每种情况的作用和意义都不一样。

同一对象,同步方法和同步this对象

一个类实例化了一个对象,这个对象可以包含多个同步方法,多个线程对这一个对象的同步方法的访问情况是:一个线程如果访问了一个同步方法,那么其它的线程无法同时访问这个对象的其它同步方法,因为同步方法锁住的是这个对象,相当于synchronized(this),所以同一时刻只能有一个线程访问这个对象的一个同步方法。这里的“同一资源”指的就是这个对象本身,即this。下面是两个同步方法示例:

public synchronized void syncMethod1() {
		System.out.println("线程 " + Thread.currentThread().getId() + " 进入 syncMethod1() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
		System.out.println(this);
		try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {
		}
		System.out.println("线程 " + Thread.currentThread().getId() + " 退出 syncMethod1() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
	}
	
	public synchronized void syncMethod2() {
		System.out.println("线程 " + Thread.currentThread().getId() + " 进入 syncMethod2() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
		System.out.println(this);
		try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {
		}
		System.out.println("线程 " + Thread.currentThread().getId() + " 退出 syncMethod2() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
	}

下面是锁住this对象的情况,和上面的同步方法功能一样,我们称为同步this对象:

public void syncThis1() {
		synchronized(this) {
			System.out.println("线程 " + Thread.currentThread().getId() + " 进入 syncThis1() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
			System.out.println(this);
			try {
				Thread.sleep(5000);
			} catch (InterruptedException e) {
			}
			System.out.println("线程 " + Thread.currentThread().getId() + " 退出 syncThis1() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
		}
	}
	
	public void syncThis2() {
		synchronized(this) {
			System.out.println("线程 " + Thread.currentThread().getId() + " 进入 syncThis2() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
			System.out.println(this);
			try {
				Thread.sleep(5000);
			} catch (InterruptedException e) {
			}
			System.out.println("线程 " + Thread.currentThread().getId() + " 退出 syncThis2() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
		}
	}

对上面四个方法的测试:

final SyncObject syncObject = new SyncObject("同一对象,同步方法和同步this对象的测试!");
		Thread t1 = new Thread(new Runnable(){
			@Override
			public void run() {
				syncObject.syncMethod1();
			}});
		Thread t2 = new Thread(new Runnable(){
			@Override
			public void run() {
				syncObject.syncMethod2();
			}});
		Thread t3 = new Thread(new Runnable(){
			@Override
			public void run() {
				syncObject.syncThis1();
			}});
		Thread t4 = new Thread(new Runnable(){
			@Override
			public void run() {
				syncObject.syncThis1();
			}});
		t1.start();
		t2.start();
		t3.start();
		t4.start();

下面是执行结果:

线程 9 进入 syncMethod2() 2012-11-08 15:32:46
SyncObject [同一对象,同步方法和同步this对象的测试!]
线程 9 退出 syncMethod2() 2012-11-08 15:32:51
线程 11 进入 syncThis1() 2012-11-08 15:32:51
SyncObject [同一对象,同步方法和同步this对象的测试!]
线程 11 退出 syncThis1() 2012-11-08 15:32:56
线程 10 进入 syncThis1() 2012-11-08 15:32:56
SyncObject [同一对象,同步方法和同步this对象的测试!]
线程 10 退出 syncThis1() 2012-11-08 15:33:01
线程 8 进入 syncMethod1() 2012-11-08 15:33:01
SyncObject [同一对象,同步方法和同步this对象的测试!]
线程 8 退出 syncMethod1() 2012-11-08 15:33:06

它们是单个的逐次执行的,与同步方法和同步this对象的情况相吻合。

同一对象,带有实例成员对象锁的同步块

还是对同一个对象的访问,同步块锁住的是一个实例成员对象,而不是一个静态的成员对象。这种情况也是多个同步块逐个的执行,因为一个线程锁住了这个对象的实例成员对象,其它的线程无法再锁住它。这里的“同一资源”指的就是这个成员对象。下面是示例代码:

public void syncBlockWithInstanceLock1() {
		synchronized(instanceLock) {
			System.out.println("线程 " + Thread.currentThread().getId() + " 进入 syncBlockWithInstanceLock1() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
			System.out.println(this);
			try {
				Thread.sleep(5000);
			} catch (InterruptedException e) {
			}
			System.out.println("线程 " + Thread.currentThread().getId() + " 退出 syncBlockWithInstanceLock1() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
		}
	}
	
	public void syncBlockWithInstanceLock2() {
		synchronized(instanceLock) {
			System.out.println("线程 " + Thread.currentThread().getId() + " 进入 syncBlockWithInstanceLock2() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
			System.out.println(this);
			try {
				Thread.sleep(5000);
			} catch (InterruptedException e) {
			}
			System.out.println("线程 " + Thread.currentThread().getId() + " 退出 syncBlockWithInstanceLock2() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
		}
	}

下面是测试代码:

final SyncObject syncObject =  new SyncObject("同一对象,使用实例对象锁的同步块的测试!");
		Thread t1 = new Thread(new Runnable(){
			@Override
			public void run() {
				syncObject.syncBlockWithInstanceLock1();
			}});
		Thread t2 = new Thread(new Runnable(){
			@Override
			public void run() {
				syncObject.syncBlockWithInstanceLock2();
			}});
		t1.start();
		t2.start();

下面是执行结果:

线程 9 进入 syncBlockWithInstanceLock2() 2012-11-08 15:37:06
SyncObject [同一对象,使用实例对象锁的同步块的测试!]
线程 9 退出 syncBlockWithInstanceLock2() 2012-11-08 15:37:11
线程 8 进入 syncBlockWithInstanceLock1() 2012-11-08 15:37:11
SyncObject [同一对象,使用实例对象锁的同步块的测试!]
线程 8 退出 syncBlockWithInstanceLock1() 2012-11-08 15:37:16

方法逐个执行,与上面分析的情况一致。

多个对象,带有实例成员对象锁的同步块

一个类实例化了多个对象,多个线程同时调用这多个对象里的带有实例成员对象锁的同步块。执行情况应该是:每一个对象内部是同步执行的,多个对象间是同时并发执行的,因为同步块锁住的是对象的实例成员对象,因为多个对象间的实例成员对象并不是同一个对象,每个对象都是一个实例,每个实例都有自己的实例成员变量。这里的“同一资源”指的是每一个对象的实例成员对象。它的示例代码和上一个是一样的,下是测试代码:

final SyncObject syncObject1 =  new SyncObject("二个对象中的对象1,使用实例对象锁的同步块的测试!");
		final SyncObject syncObject2 =  new SyncObject("二个对象中的对象2,使用实例对象锁的同步块的测试!");
		
		Thread t1 = new Thread(new Runnable(){
			@Override
			public void run() {
				syncObject1.syncBlockWithInstanceLock1();
			}});
		Thread t2 = new Thread(new Runnable(){
			@Override
			public void run() {
				syncObject1.syncBlockWithInstanceLock2();
			}});
		Thread t3 = new Thread(new Runnable(){
			@Override
			public void run() {
				syncObject2.syncBlockWithInstanceLock1();
			}});
		Thread t4 = new Thread(new Runnable(){
			@Override
			public void run() {
				syncObject2.syncBlockWithInstanceLock2();
			}});
		t1.start();
		t2.start();
		t3.start();
		t4.start();

下面是执行的结果:

线程 8 进入 syncBlockWithInstanceLock1() 2012-11-08 15:57:24
SyncObject [二个对象中的对象1,使用实例对象锁的同步块的测试!]
线程 11 进入 syncBlockWithInstanceLock2() 2012-11-08 15:57:24
SyncObject [二个对象中的对象2,使用实例对象锁的同步块的测试!]
线程 8 退出 syncBlockWithInstanceLock1() 2012-11-08 15:57:29
线程 9 进入 syncBlockWithInstanceLock2() 2012-11-08 15:57:29
SyncObject [二个对象中的对象1,使用实例对象锁的同步块的测试!]
线程 11 退出 syncBlockWithInstanceLock2() 2012-11-08 15:57:29
线程 10 进入 syncBlockWithInstanceLock1() 2012-11-08 15:57:29
SyncObject [二个对象中的对象2,使用实例对象锁的同步块的测试!]
线程 9 退出 syncBlockWithInstanceLock2() 2012-11-08 15:57:34
线程 10 退出 syncBlockWithInstanceLock1() 2012-11-08 15:57:34

可以看出,同一对象内部是同步执行的,多个对象间是同时并发执行的。

同一对象,带有静态成员对象锁的同步块

一个类实例化一个对象,同步块锁住的是这个对象的静态成员对象。这种情况肯定是逐个执行的,因为静态成员是属于类本身所有的,多个实例对象都共享一份。这里的“同一资源”指的就是这个静态的成员对象。下面是实例代码:

public void syncBlockWithStaticLock1() {
		synchronized(staticLock) {
			System.out.println("线程 " + Thread.currentThread().getId() + " 进入 syncBlockWithStaticLock1() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
			System.out.println(this);
			try {
				Thread.sleep(5000);
			} catch (InterruptedException e) {
			}
			System.out.println("线程 " + Thread.currentThread().getId() + " 退出 syncBlockWithStaticLock1() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
		}
	}
	
	public void syncBlockWithStaticLock2() {
		synchronized(staticLock) {
			System.out.println("线程 " + Thread.currentThread().getId() + " 进入 syncBlockWithStaticLock2() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
			System.out.println(this);
			try {
				Thread.sleep(5000);
			} catch (InterruptedException e) {
			}
			System.out.println("线程 " + Thread.currentThread().getId() + " 退出 syncBlockWithStaticLock2() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
		}
	}

下面是测试代码:

final SyncObject syncObject = new SyncObject("同一对象,使用静态对象锁的同步块的测试!");
		Thread t1 = new Thread(new Runnable(){
			@Override
			public void run() {
				syncObject.syncBlockWithStaticLock1();
			}});
		Thread t2 = new Thread(new Runnable(){
			@Override
			public void run() {
				syncObject.syncBlockWithStaticLock2();
			}});
		t1.start();
		t2.start();

下面是执行的结果:

线程 9 进入 syncBlockWithStaticLock2() 2012-11-08 16:10:54
SyncObject [同一对象,使用静态对象锁的同步块的测试!]
线程 9 退出 syncBlockWithStaticLock2() 2012-11-08 16:10:59
线程 8 进入 syncBlockWithStaticLock1() 2012-11-08 16:10:59
SyncObject [同一对象,使用静态对象锁的同步块的测试!]
线程 8 退出 syncBlockWithStaticLock1() 2012-11-08 16:11:04

方法是逐个执行的,与理论一致。

多个对象,带有静态成员对象锁的同步块

一个类实例化多个对象,多个线程同时访问锁住静态成员对象的同步块,这种情况下,不仅对象内是逐个同步执行的,对象间也是逐个同步执行的。因为静态成员对象是属于类本身所有,类的多个实例对象都共享一份静态成员,即静态成员对象只有一个,这里的“同一资源”就是指的这个静态成员对象。示例代码和上一个是一样的,下面是测试的代码:

final SyncObject syncObject1 =  new SyncObject("二个对象中的对象1,使用静态对象锁的同步块的测试!");
		final SyncObject syncObject2 =  new SyncObject("二个对象中的对象2,使用静态对象锁的同步块的测试!");
		
		Thread t1 = new Thread(new Runnable(){
			@Override
			public void run() {
				syncObject1.syncBlockWithStaticLock1();
			}});
		Thread t2 = new Thread(new Runnable(){
			@Override
			public void run() {
				syncObject1.syncBlockWithStaticLock2();
			}});
		Thread t3 = new Thread(new Runnable(){
			@Override
			public void run() {
				syncObject2.syncBlockWithStaticLock1();
			}});
		Thread t4 = new Thread(new Runnable(){
			@Override
			public void run() {
				syncObject2.syncBlockWithStaticLock2();
			}});
		t1.start();
		t2.start();
		t3.start();
		t4.start();

下面是执行的结果:

线程 8 进入 syncBlockWithStaticLock1() 2012-11-08 16:19:54
SyncObject [二个对象中的对象1,使用静态对象锁的同步块的测试!]
线程 8 退出 syncBlockWithStaticLock1() 2012-11-08 16:19:59
线程 11 进入 syncBlockWithStaticLock2() 2012-11-08 16:19:59
SyncObject [二个对象中的对象2,使用静态对象锁的同步块的测试!]
线程 11 退出 syncBlockWithStaticLock2() 2012-11-08 16:20:04
线程 9 进入 syncBlockWithStaticLock2() 2012-11-08 16:20:04
SyncObject [二个对象中的对象1,使用静态对象锁的同步块的测试!]
线程 9 退出 syncBlockWithStaticLock2() 2012-11-08 16:20:09
线程 10 进入 syncBlockWithStaticLock1() 2012-11-08 16:20:09
SyncObject [二个对象中的对象2,使用静态对象锁的同步块的测试!]
线程 10 退出 syncBlockWithStaticLock1() 2012-11-08 16:20:14

可以看出,对个对象的多个同步块都是逐个同步执行的。

静态同步方法

上面我们说到实例的同步方法锁住的是实例对象this,那么静态的同步方法锁住的就是类本身,即类的Class对象,因为Class对象存储了类本身的所有元数据信息。这种情况就相当于synchronized(SyncObject.class)。因为一个类只有一个Class对象,所以静态同步方法是逐个的同步执行的。这里的“同一资源”指的就是类的Class对象,下面是实例代码:

public synchronized static void syncStaticMethod1(String text) {
		System.out.println("线程 " + Thread.currentThread().getId() + " 进入 syncStaticMethod1() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
		System.out.println(new SyncObject(text));
		try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {
		}
		System.out.println("线程 " + Thread.currentThread().getId() + " 退出 syncStaticMethod1() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
	}
	
	public synchronized static void syncStaticMethod2(String text) {
		System.out.println("线程 " + Thread.currentThread().getId() + " 进入 syncStaticMethod2() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
		System.out.println(new SyncObject(text));
		try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {
		}
		System.out.println("线程 " + Thread.currentThread().getId() + " 退出 syncStaticMethod2() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
	}

下面是我们自己锁住类的Class对象的情况,和上面在功能上是一样的:

public static void syncClass1(String text) {
		synchronized(SyncObject.class) {
			System.out.println("线程 " + Thread.currentThread().getId() + " 进入 syncClass1() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
			System.out.println(new SyncObject(text));
			try {
				Thread.sleep(5000);
			} catch (InterruptedException e) {
			}
			System.out.println("线程 " + Thread.currentThread().getId() + " 退出 syncClass1() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
		}
	}
	
	public static void syncClass2(String text) {
		synchronized(SyncObject.class) {
			System.out.println("线程 " + Thread.currentThread().getId() + " 进入 syncClass2() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
			System.out.println(new SyncObject(text));
			try {
				Thread.sleep(5000);
			} catch (InterruptedException e) {
			}
			System.out.println("线程 " + Thread.currentThread().getId() + " 退出 syncClass2() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
		}
	}

下面是测试代码:

Thread t1 = new Thread(new Runnable(){
			@Override
			public void run() {
				SyncObject.syncStaticMethod1("静态同步方法和同步类的测试!");
			}});
		Thread t2 = new Thread(new Runnable(){
			@Override
			public void run() {
				SyncObject.syncStaticMethod2("静态同步方法和同步类的测试!");
			}});
		Thread t3 = new Thread(new Runnable(){
			@Override
			public void run() {
				SyncObject.syncClass1("静态同步方法和同步类的测试!");
			}});
		Thread t4 = new Thread(new Runnable(){
			@Override
			public void run() {
				SyncObject.syncClass2("静态同步方法和同步类的测试!");
			}});
		t1.start();
		t2.start();
		t3.start();
		t4.start();

下面是执行结果:

线程 9 进入 syncStaticMethod2() 2012-11-08 16:30:39
SyncObject [静态同步方法和同步类的测试!]
线程 9 退出 syncStaticMethod2() 2012-11-08 16:30:44
线程 11 进入 syncClass2() 2012-11-08 16:30:44
SyncObject [静态同步方法和同步类的测试!]
线程 11 退出 syncClass2() 2012-11-08 16:30:49
线程 10 进入 syncClass1() 2012-11-08 16:30:49
SyncObject [静态同步方法和同步类的测试!]
线程 10 退出 syncClass1() 2012-11-08 16:30:54
线程 8 进入 syncStaticMethod1() 2012-11-08 16:30:54
SyncObject [静态同步方法和同步类的测试!]
线程 8 退出 syncStaticMethod1() 2012-11-08 16:30:59

可以看出,多个静态同步方法是逐个的同步执行的。

静态同步块

位于一个静态方法里面的同步块锁住了一个静态成员对象,这种情况是逐个同步执行的,因为静态成员属于类本身,只有一份。这里的“同一资源”指的就是这个静态的成员对象。下面是实例代码:

public static void syncStaticBlock1(String text) {
		synchronized(staticLock) {
			System.out.println("线程 " + Thread.currentThread().getId() + " 进入 syncStaticBlock1() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
			System.out.println(new SyncObject(text));
			try {
				Thread.sleep(5000);
			} catch (InterruptedException e) {
			}
			System.out.println("线程 " + Thread.currentThread().getId() + " 退出 syncStaticBlock1() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
		}
	}
	
	public static void syncStaticBlock2(String text) {
		synchronized(staticLock) {
			System.out.println("线程 " + Thread.currentThread().getId() + " 进入 syncStaticBlock2() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
			System.out.println(new SyncObject(text));
			try {
				Thread.sleep(5000);
			} catch (InterruptedException e) {
			}
			System.out.println("线程 " + Thread.currentThread().getId() + " 退出 syncStaticBlock2() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
		}
	}

下面是测试代码:

Thread t1 = new Thread(new Runnable(){
			@Override
			public void run() {
				SyncObject.syncStaticBlock1("静态同步块的测试!");
			}});
		Thread t2 = new Thread(new Runnable(){
			@Override
			public void run() {
				SyncObject.syncStaticBlock2("静态同步块的测试!");
			}});
		t1.start();
		t2.start();

下面是执行结果:

线程 9 进入 syncStaticBlock2() 2012-11-08 16:40:36
SyncObject [静态同步块的测试!]
线程 9 退出 syncStaticBlock2() 2012-11-08 16:40:41
线程 8 进入 syncStaticBlock1() 2012-11-08 16:40:41
SyncObject [静态同步块的测试!]
线程 8 退出 syncStaticBlock1() 2012-11-08 16:40:46

静态同步块是逐个同步执行的。

本文使用的SyncObject类的代码

public class SyncObject {

	private byte[] instanceLock = new byte[0];
	private static byte[] staticLock = new byte[0];
	
	private String text;
	public SyncObject(String text) {
		this.text = text;
	}
	
	public synchronized void syncMethod1() {
		System.out.println("线程 " + Thread.currentThread().getId() + " 进入 syncMethod1() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
		System.out.println(this);
		try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {
		}
		System.out.println("线程 " + Thread.currentThread().getId() + " 退出 syncMethod1() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
	}
	
	public synchronized void syncMethod2() {
		System.out.println("线程 " + Thread.currentThread().getId() + " 进入 syncMethod2() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
		System.out.println(this);
		try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {
		}
		System.out.println("线程 " + Thread.currentThread().getId() + " 退出 syncMethod2() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
	}
	
	public void syncThis1() {
		synchronized(this) {
			System.out.println("线程 " + Thread.currentThread().getId() + " 进入 syncThis1() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
			System.out.println(this);
			try {
				Thread.sleep(5000);
			} catch (InterruptedException e) {
			}
			System.out.println("线程 " + Thread.currentThread().getId() + " 退出 syncThis1() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
		}
	}
	
	public void syncThis2() {
		synchronized(this) {
			System.out.println("线程 " + Thread.currentThread().getId() + " 进入 syncThis2() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
			System.out.println(this);
			try {
				Thread.sleep(5000);
			} catch (InterruptedException e) {
			}
			System.out.println("线程 " + Thread.currentThread().getId() + " 退出 syncThis2() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
		}
	}
	
	public void syncBlockWithInstanceLock1() {
		synchronized(instanceLock) {
			System.out.println("线程 " + Thread.currentThread().getId() + " 进入 syncBlockWithInstanceLock1() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
			System.out.println(this);
			try {
				Thread.sleep(5000);
			} catch (InterruptedException e) {
			}
			System.out.println("线程 " + Thread.currentThread().getId() + " 退出 syncBlockWithInstanceLock1() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
		}
	}
	
	public void syncBlockWithInstanceLock2() {
		synchronized(instanceLock) {
			System.out.println("线程 " + Thread.currentThread().getId() + " 进入 syncBlockWithInstanceLock2() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
			System.out.println(this);
			try {
				Thread.sleep(5000);
			} catch (InterruptedException e) {
			}
			System.out.println("线程 " + Thread.currentThread().getId() + " 退出 syncBlockWithInstanceLock2() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
		}
	}
	
	public void syncBlockWithStaticLock1() {
		synchronized(staticLock) {
			System.out.println("线程 " + Thread.currentThread().getId() + " 进入 syncBlockWithStaticLock1() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
			System.out.println(this);
			try {
				Thread.sleep(5000);
			} catch (InterruptedException e) {
			}
			System.out.println("线程 " + Thread.currentThread().getId() + " 退出 syncBlockWithStaticLock1() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
		}
	}
	
	public void syncBlockWithStaticLock2() {
		synchronized(staticLock) {
			System.out.println("线程 " + Thread.currentThread().getId() + " 进入 syncBlockWithStaticLock2() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
			System.out.println(this);
			try {
				Thread.sleep(5000);
			} catch (InterruptedException e) {
			}
			System.out.println("线程 " + Thread.currentThread().getId() + " 退出 syncBlockWithStaticLock2() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
		}
	}
	
	public synchronized static void syncStaticMethod1(String text) {
		System.out.println("线程 " + Thread.currentThread().getId() + " 进入 syncStaticMethod1() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
		System.out.println(new SyncObject(text));
		try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {
		}
		System.out.println("线程 " + Thread.currentThread().getId() + " 退出 syncStaticMethod1() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
	}
	
	public synchronized static void syncStaticMethod2(String text) {
		System.out.println("线程 " + Thread.currentThread().getId() + " 进入 syncStaticMethod2() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
		System.out.println(new SyncObject(text));
		try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {
		}
		System.out.println("线程 " + Thread.currentThread().getId() + " 退出 syncStaticMethod2() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
	}
	
	public static void syncClass1(String text) {
		synchronized(SyncObject.class) {
			System.out.println("线程 " + Thread.currentThread().getId() + " 进入 syncClass1() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
			System.out.println(new SyncObject(text));
			try {
				Thread.sleep(5000);
			} catch (InterruptedException e) {
			}
			System.out.println("线程 " + Thread.currentThread().getId() + " 退出 syncClass1() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
		}
	}
	
	public static void syncClass2(String text) {
		synchronized(SyncObject.class) {
			System.out.println("线程 " + Thread.currentThread().getId() + " 进入 syncClass2() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
			System.out.println(new SyncObject(text));
			try {
				Thread.sleep(5000);
			} catch (InterruptedException e) {
			}
			System.out.println("线程 " + Thread.currentThread().getId() + " 退出 syncClass2() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
		}
	}
	
	public static void syncStaticBlock1(String text) {
		synchronized(staticLock) {
			System.out.println("线程 " + Thread.currentThread().getId() + " 进入 syncStaticBlock1() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
			System.out.println(new SyncObject(text));
			try {
				Thread.sleep(5000);
			} catch (InterruptedException e) {
			}
			System.out.println("线程 " + Thread.currentThread().getId() + " 退出 syncStaticBlock1() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
		}
	}
	
	public static void syncStaticBlock2(String text) {
		synchronized(staticLock) {
			System.out.println("线程 " + Thread.currentThread().getId() + " 进入 syncStaticBlock2() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
			System.out.println(new SyncObject(text));
			try {
				Thread.sleep(5000);
			} catch (InterruptedException e) {
			}
			System.out.println("线程 " + Thread.currentThread().getId() + " 退出 syncStaticBlock2() " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
		}
	}
	
	@Override
	public String toString() {
		return "SyncObject [" + text + "]";
	}
	
}

你可能感兴趣的:(Java线程)