在多线程访问同一个对象中的不同的synchronized方法或synchronized代码块的前提下,也就是“对象监控器”为同一个对象的时候,也就是synchronized的锁为同一把锁的时候,调用的效果就是:当前正在执行的synchronized方法或synchronized代码块的运行结果是同步的,但是对其synchronized方法或synchronized代码块来说是阻塞的。同步是因为当一个线程执行synchronized方法或代码块的时候,正常情况下,别的线程永远得不到CPU的执行机会。也就是因为别的线程永远得不到执行机会,所以其他synchronized方法和synchronized代码块没有机会被执行,造成阻塞。

   其实Java还支持“任意对象”作为“对象监视器”,来实现同步的功能,这个“任意对象”大多数为实例变量或者方法形参,使用的格式为synchronized(非this对象)同步代码块。那么她的特点和synchronized(this)代码块是一样的,特点如下:在多个线程持有“对象监视器”为同一个对象的前提下,同一时间只有一个线程可以执行synchronized(非this对象)代码块里的代码。我写了一个小例子来证明,代码如下:

public static void main(String[] args) {

		MyService1 service = new MyService1();
		ThreadA a = new ThreadA(service);
		a.setName("A");
		ThreadB b = new ThreadB(service);
		b.setName("B");
		a.start();
		b.start();
	}

	public static class ThreadA extends Thread {

		private MyService1 service;

		public ThreadA(MyService1 service) {
			super();
			this.service = service;
		}

		@Override
		public void run() {

			super.run();
			service.serviceMethodA("a", "A");

		}
	}

	public static class ThreadB extends Thread {

		private MyService1 service;

		public ThreadB(MyService1 service) {
			super();
			this.service = service;
		}

		@Override
		public void run() {

			super.run();
			service.serviceMethodA("b", "B");

		}
	}
}

class MyService1 {

	private String userName, userPassWord;
	String s = new String();

	public void serviceMethodA(String userName, String userPassWord) {
		synchronized (s) {

			try {
				System.out.println("线程" + Thread.currentThread().getName()
						+ "在" + System.currentTimeMillis() + "进入同步块");
				Thread.sleep(5000);
				System.out.println("线程" + Thread.currentThread().getName()
						+ "在" + System.currentTimeMillis() + "离开同步块");
			} catch (InterruptedException e) {

				e.printStackTrace();
			}
		}
	}

}

运行结果如下:从代码上可以看到,线程A和线程B访问的都是service这个对象,所以“对象监控器”为同一个对象,理论上,在这种情况,执行的结果应该是同步的,从控制台打印的结果来看,也确实是同步的。

          

java completefuture 多线程异步查询结果汇总 java多线程synchronized_System

那么synchronized(非this对象)有什么优点呢,我们假设在一个类中有很多synchronized修饰的方法,虽然可以实现同步,但是同时也形成了阻塞,这样就影响了运行效率,但是使用同步代码块非this锁就可以解决这个问题,因为非this锁和this锁是异步的,他们之间不会互相争夺锁,这样运行效率就提高了。下面看一个例子来证明这件事情,只需要在MyService1类里添加一个方法即可,然后线程B调用该方法。代码如下:

public void serviceMethodB(String userName, String userPassWord) {
		synchronized (this) {

			try {
				System.out.println("线程" + Thread.currentThread().getName()
						+ "在" + System.currentTimeMillis() + "进入同步块");
				Thread.sleep(5000);
				System.out.println("线程" + Thread.currentThread().getName()
						+ "在" + System.currentTimeMillis() + "离开同步块");
			} catch (InterruptedException e) {

				e.printStackTrace();
			}
		}
	}

运行结果如下:由于“对象监视器”不同,所以运行的结果是异步的,这个异步说的是方法serviceMethodA和方法serviceMethodB之间是异步的,交叉执行的。

      

java completefuture 多线程异步查询结果汇总 java多线程synchronized_ide_02

上面说过了多个线程同时访问synchronized(非this对象)代码块时,呈同步效果,也就是说必须一个线程执行完释放掉锁,另一个线程才可以执行。也说过了多个线程分别访问this锁和非this锁,呈异步效果,可以提高运行效率。接下来说一说多线程访问不同的对象是什么效果,也就是使用不同的“对象监视器”。下面看一个例子,代码如下:

public static void main(String[] args) {

		MyService4 service = new MyService4();
		MyObject1 object = new MyObject1();
		MyObject1 object1 = new MyObject1();
//两个线程传入不同的对象
		ThreadA a = new ThreadA(service, object);
		a.setName("A");
		ThreadB b = new ThreadB(service, object1);
		b.setName("B");
		a.start();
		b.start();
	}

	public static class ThreadA extends Thread {

		private MyService4 service;
		private MyObject1 object;

		public ThreadA(MyService4 service, MyObject1 object) {
			super();
			this.service = service;
			this.object = object;
		}

		@Override
		public void run() {

			super.run();
			service.serviceMethod(object);

		}
	}

	public static class ThreadB extends Thread {

		private MyService4 service;
		private MyObject1 object;

		public ThreadB(MyService4 service, MyObject1 object) {
			super();
			this.service = service;
			this.object = object;
		}

		@Override
		public void run() {

			super.run();
			service.serviceMethod(object);

		}
	}
}

class MyService4 {

	public void serviceMethod(MyObject1 object) {
		synchronized (object) {

			try {
				System.out.println("线程" + Thread.currentThread().getName()
						+ "在" + System.currentTimeMillis() + "进入同步块");
				Thread.sleep(5000);
				System.out.println("线程" + Thread.currentThread().getName()
						+ "在" + System.currentTimeMillis() + "离开同步块");
			} catch (InterruptedException e) {

				e.printStackTrace();
			}
		}
	}

}

class MyObject1 {
}

运行结果如下:由结果可以看出来,如果使用不同的“对象监视器”,结果是异步执行的。       

java completefuture 多线程异步查询结果汇总 java多线程synchronized_代码块_03