Synchronized
Java编程思想:每个对象都包含了一把锁(也叫作“监视器”),它自动成为对象的一部分,调用任何synchronized方法时,对象就会被锁定,不可再调用那个对象的其他任何synchronized 方法,除非第一个方法完成了自己的工作,并解除锁定。
特点:Jvm层面,非公平,悲观,独占,可重入,重量级。
作用:修饰方法和代码块。
修饰方法和代码块
synchronized修饰静态方法,我们可以称其为“类锁”,即只要有一个线程实例对象获取该锁,其他线程实例对象都需要等待。修饰非静态方法,我们称之为对象锁,即不同的线程实例对象是可以调用同一类下的同步方法。
/** * @PackageName com.a.squirrel.synchronize * @Author: squirrel * @Date: 2018/6/25 10:04 * @Description: synchronized解析辅助类 */ public class SynchronizedDescription { private String tmpStr; private int tmpInt; /** * @Author squirrel * @Description 非静态同步方法 * @Date 2018/6/25 * @Param [synchronizedDescription] * @return **/ public synchronized void testSynchronizedMethod(SynchronizedDescription synchronizedDescription){ System.out.println("线程:"+synchronizedDescription.getTmpInt()+"-->:==========我是非静态同步方法======="); System.out.println("线程:"+synchronizedDescription.getTmpInt()+"-->:调用非静态同步方法时间为:"+getNowTime()); try { Thread.sleep(5000);// 当前线程休眠5s,休眠过程中不会释放锁 } catch (InterruptedException e) { e.printStackTrace(); } } /** * @Author squirrel * @Description 同步代码块 * @Date 2018/6/25 * @Param [synchronizedDescription] * @return **/ public void testSynchronizedBlockMethod(SynchronizedDescription synchronizedDescription){ synchronized (synchronizedDescription){// 锁定实例对象 System.out.println("线程:"+synchronizedDescription.getTmpInt()+"-->:==========我是同步代码块======="); System.out.println("线程:"+synchronizedDescription.getTmpInt()+"-->:调用同步代码块时间为:"+getNowTime()); try { Thread.sleep(2000);// 当前线程休眠2s,休眠过程中不会释放锁 } catch (InterruptedException e) { e.printStackTrace(); } } } /** * @Author squirrel * @Description 静态同步方法 * @Date 2018/6/25 * @Param [synchronizedDescription] * @return **/ public synchronized static void testSynchronizedStaticMethod(SynchronizedDescription synchronizedDescription){ System.out.println("线程:"+synchronizedDescription.getTmpInt()+"-->:==========我是静态同步方法======="); System.out.println("线程:"+synchronizedDescription.getTmpInt()+"-->:调用静态同步方法时间为:"+getNowTime()); try { Thread.sleep(10000);// 当前线程休眠10s,休眠过程中不会释放锁 } catch (InterruptedException e) { e.printStackTrace(); } } /** * @Author squirrel * @Description 获取当前时间 * @Date 2018/6/25 * @Param [] * @return java.lang.String **/ private static String getNowTime(){ return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()); } public SynchronizedDescription(String tmpStr, int tmpInt) { this.tmpStr = tmpStr; this.tmpInt = tmpInt; } public String getTmpStr() { return tmpStr; } public void setTmpStr(String tmpStr) { this.tmpStr = tmpStr; } public int getTmpInt() { return tmpInt; } public void setTmpInt(int tmpInt) { this.tmpInt = tmpInt; } }
/** * @PackageName com.a.squirrel.synchronize * @Author: squirrel * @Date: 2018/6/25 10:10 * @Description: 测试类 */ public class TestSynchronized { public static void main(String[] args) { // 创建阻塞队列 final BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(100); // 创建线程池 final ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2,20,60, TimeUnit.SECONDS,queue); threadPool.allowCoreThreadTimeOut(true); for (int i =0;i<100;i++){ threadPool.execute(new Runnable() { @Override public void run() { final String tmpStr = Thread.currentThread().getName(); final String[] split = tmpStr.split("-"); int tmpInt = Integer.parseInt(split[split.length-1]); SynchronizedDescription synchronizedDescription = new SynchronizedDescription(tmpStr,tmpInt); // 调用同步代码块 synchronizedDescription.testSynchronizedBlockMethod(synchronizedDescription); // 调用非静态同步方法 synchronizedDescription.testSynchronizedMethod(synchronizedDescription); // 调用静态同步方法 synchronizedDescription.testSynchronizedStaticMethod(synchronizedDescription); } }); } } }
运行结果可以验证以上结论:
下面我们变更同步代码块的同步对象:
/** * @Author squirrel * @Description 同步代码块 * @Date 2018/6/25 * @Param [synchronizedDescription] * @return **/ public void testSynchronizedBlockMethod(SynchronizedDescription synchronizedDescription){ synchronized (SynchronizedDescription.class){// 锁定类对象 System.out.println("线程:"+synchronizedDescription.getTmpInt()+"-->:==========我是同步代码块======="); System.out.println("线程:"+synchronizedDescription.getTmpInt()+"-->:调用同步代码块时间为:"+getNowTime()); try { Thread.sleep(2000);// 当前线程休眠2s,休眠过程中不会释放锁 } catch (InterruptedException e) { e.printStackTrace(); } } }
由上图我们可以得出一个结论,这里借用一张图来说明一下这个结论:
实现原理:
深入理解Java虚拟机:对象在内存中存储的布局可以分为3块区域:对象头,实例数据和对齐填充。
synchronized对象锁其指针指向的是一个monitor对象,每个对象实例都会有一个 monitor,其中monitor可以与对象一起创建销毁,也可以在线程试图获取对象锁时自动生成。在执行monitorenter指令时,首先要尝试获取对象锁,如果这个对象没有被锁定,或者当前线程已经拥有了这个对象的锁,那么就把锁计数器加1,当执行monitorexit指令时,释放锁同时锁计数器也会减1。
来源:https://www.cnblogs.com/yzss/p/10984666.html