zoukankan      html  css  js  c++  java
  • 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 { }

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

             

  • 相关阅读:
    1293E. Xenon's Attack on the Gangs (树形DP)
    二分check的妙用
    Educational Codeforces Round 80 (CF
    CodeForces Goodbye2019 E.Divide Points (构造)
    POJ 1061 (拓展欧几里得+求最小正整数解)
    1238D
    关于Mysql用户的相关操作
    JAVA类的符号引用的理解
    关于tomcat的路径等基础问题
    Java 方法中,参数的装配顺序
  • 原文地址:https://www.cnblogs.com/chentong/p/5660801.html
Copyright © 2011-2022 走看看