• Java多线程之synchronized(五)


         上篇介绍了用synchronized修饰static方式来实现“Class 锁”,今天要介绍另一种实现方式,synchronized(class)代码块,写法不一样但是作用是一样的。下面我附上一段代码来看一下synchronized(class)代码块的基本用法,如下:

    public static void main(String[] args) {
    
    		Service4 s1 = new Service4();
    		Service4 s2 = new Service4();
    		ThreadA a = new ThreadA(s1);
    		ThreadB b = new ThreadB(s2);
    		a.setName("A");
    		b.setName("B");
    		a.start();
    		b.start();
    	}
    
    	public static class ThreadA extends Thread {
    
    		private Service4 service;
    
    		public ThreadA(Service4 service) {
    			super();
    			this.service = service;
    		}
    
    		@Override
    		public void run() {
    
    			super.run();
    			service.printA();
    		}
    	}
    
    	public static class ThreadB extends Thread {
    
    		private Service4 service;
    
    		public ThreadB(Service4 service) {
    			super();
    			this.service = service;
    		}
    
    		@Override
    		public void run() {
    
    			super.run();
    			service.printB();
    		}
    	}
    
    }
    
    class Service4 {
    
    	static public void printA() {
    		synchronized (Service4.class) {
    			try {
    				System.out.println("线程:" + Thread.currentThread().getName()
    						+ "在" + System.currentTimeMillis() + "进入printA");
    				Thread.sleep(3000);
    				System.out.println("线程:" + Thread.currentThread().getName()
    						+ "在" + System.currentTimeMillis() + "离开printA");
    			} catch (InterruptedException e) {
    
    				e.printStackTrace();
    			}
    		}
    
    	}
    
    	static public void printB() {
    		synchronized (Service4.class) {
    			System.out.println("线程:" + Thread.currentThread().getName() + "在"
    					+ System.currentTimeMillis() + "进入printB");
    			try {
    				Thread.sleep(3000);
    			} catch (InterruptedException e) {
    
    				e.printStackTrace();
    			}
    			System.out.println("线程:" + Thread.currentThread().getName() + "在"
    					+ System.currentTimeMillis() + "离开printB");
    		}
    	}
    
    }

          运行结果如下:synchronized(class)代码块的作用和synchronized static的作用是一样的

        

           以前我说过,synchronized还可以传入其他的实例对象或者方法的形参,那么我现在要说一种把synchronized(class)和String一起使用的特殊情况,还是用代码讲解,下面我附上一段代码,如下:  
    	public static void main(String[] args) {
    
    		Service5 service = new Service5();
    		ThreadA a = new ThreadA(service);
    		a.setName("A");
    		a.start();
    		ThreadB b = new ThreadB(service);
    		b.setName("B");
    		b.start();
    	}
    
    	public static class ThreadB extends Thread {
    		private Service5 service;
    
    		public ThreadB(Service5 service) {
    			super();
    			this.service = service;
    		}
    
    		@Override
    		public void run() {
    			// TODO Auto-generated method stub
    			super.run();
    			service.print("AA");
    		}
    	}
    
    	public static class ThreadA extends Thread {
    		private Service5 service;
    
    		public ThreadA(Service5 service) {
    			super();
    			this.service = service;
    		}
    
    		@Override
    		public void run() {
    			// TODO Auto-generated method stub
    			super.run();
    			service.print("AA");
    		}
    	}
    }
    
    class Service5 {
    	public static void print(String string) {
    
    		try {
    			synchronized (string) {
    				while (true) {
    
    					System.out.println(Thread.currentThread().getName());
    					Thread.sleep(1000);
    				}
    			}
    
    		} catch (InterruptedException e) {
    
    			e.printStackTrace();
    		}
    
    	}
    }
    
       运行结果如下:可以看到输出结果会打印出无数个连续的A,这是由于在JVM中有String常量池缓存的功能,所以说printA()和printB()两个方法里传进来的“AA”是同一个值,因此两个线程持有相同的锁,所以总有一个线程执行不到。

         

          上面已经看到了常量池带来的问题,因此大多情况下,都不用String最为对像锁,而改用其他的,比如new Object()实例化一个Object对象。可以看看下面的例子,运行后的区别在哪,如下:

    	public static void main(String[] args) {
    
    		Service6 service = new Service6();
    		ThreadA a = new ThreadA(service);
    		a.setName("A");
    		a.start();
    		ThreadB b = new ThreadB(service);
    		b.setName("B");
    		b.start();
    	}
    
    	public static class ThreadB extends Thread {
    		private Service6 service;
    
    		public ThreadB(Service6 service) {
    			super();
    			this.service = service;
    		}
    
    		@Override
    		public void run() {
    			// TODO Auto-generated method stub
    			super.run();
    			service.print(new Object());
    		}
    	}
    
    	public static class ThreadA extends Thread {
    		private Service6 service;
    
    		public ThreadA(Service6 service) {
    			super();
    			this.service = service;
    		}
    
    		@Override
    		public void run() {
    			// TODO Auto-generated method stub
    			super.run();
    			service.print(new Object());
    		}
    	}
    }
    
    class Service6 {
    	
    	public static void print(Object object) {
    
    		try {
    			synchronized (object) {
    				while (true) {
    
    					System.out.println(Thread.currentThread().getName());
    					Thread.sleep(1000);
    				}
    			}
    
    		} catch (InterruptedException e) {
    
    			e.printStackTrace();
    		}
    
    	}
    }
    

          运行结果如下:可以看到运行结果是交叉的异步的,说明两个线程持有的锁不是同一把锁。

              

     

            
  • 相关阅读:
    前中后序建立树或者直接历遍
    Leetcode:面试题 04.03. 特定深度节点链表
    按层数层序历遍
    Solidity函数修饰符
    无线传感网定位技术
    无线传感器网络概述,传感器网络结构
    Solidity高级用法
    智能合约交互
    内存
    CPU的态
  • 原文地址:https://www.cnblogs.com/chentong/p/5663629.html
Copyright © 2020-2023  润新知