Java多线程之synchronized(三)

        在多线程访问同一个对象中的不同的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这个对象,所以“对象监控器”为同一个对象,理论上,在这种情况,执行的结果应该是同步的,从控制台打印的结果来看,也确实是同步的。

          

          那么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之间是异步的,交叉执行的。

      

        上面说过了多个线程同时访问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 { }

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

         

 

posted @ 2016-07-11 16:51  陈家小桐桐  阅读(207)  评论(0编辑  收藏  举报