摘要:也有人称其为同步锁。既然是锁,其必然有锁的东西,下面先会简单介绍一下,再通过一个示例代码展示锁了什么。从而可以证明并不是锁定方法内访问的变量锁定的是同一个监视器对象监视的代码
前言
synchronized翻译为中文的意思是同步的,它是Java中处理线程安全问题常用的关键字。也有人称其为同步锁。既然是锁,其必然有锁的东西,下面先会简单介绍一下synchronized,再通过一个示例代码展示synchronized锁了什么。(这里先提前透露答案synchronized锁的是代码)
介绍 定义synchronized提供的同步机制确保了同一个时刻,被修饰的代码块或方法只会有一个线程执行。
用法synchronized可以修饰方法和代码块:
修饰普通方法
修饰静态方法
修饰代码块
根据修饰情况,分为对象锁和类锁:
对象锁:
普通方法(等价于代码块修饰this)
代码块修饰的是是类的一个对象
类锁
类方法(等价于代码块修饰当前类Class对象)
代码块修饰的是是类Class对象
原理synchronized底层原理是使用了对象持有的监视器(monitor)。但是同步代码块和同步方法的原理存在一点差异:
同步代码块是使用monitorenter和monitorexit指令实现的
同步方法是由方法调用指令读取运行时常量池中方法的ACC_SYNCHRONIZED 标识隐式实现,实际上还是调用了monitorenter和monitorexit指令
测试示例 计数器一个特殊的计数器,自增方法increase()被synchronized修饰,而获取当前值方法getCurrent()则没有被synchronized修饰。
/** * 计数器 * @author RJH * create at 2019-03-13 */ public class Counter { /** * 全局对象,总数 */ private static int i = 0; /** * 自增 * @return */ public synchronized int increase() { try { //使用休眠让结果更明显 Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } return ++i; } /** * 获取当前值 * @return */ public int getCurrent() { return i; } }测试代码
使用自增线程和获取当前值的线程来验证synchronized锁的是代码,而不是全局变量
/** * synchronized锁了什么 * @author RJH * create at 2019-03-02 */ public class LockWhatTest { public static void main(String[] args) { Counter counter =new Counter(); IncreaseThread increaseThread1=new IncreaseThread(counter); IncreaseThread increaseThread2=new IncreaseThread(counter); GetThread getThread=new GetThread(counter); increaseThread1.start(); increaseThread2.start(); //直到increaseThread的线程启动才执行下一步 while (increaseThread1.getState().compareTo(Thread.State.NEW)==0 && increaseThread1.getState().compareTo(Thread.State.NEW)==0){ } getThread.start(); } /** * 自增线程 */ static class IncreaseThread extends Thread{ private Counter counter; public IncreaseThread(Counter counter) { this.counter = counter; } @Override public void run() { System.out.println("After increase:" + counter.increase()+",trigger time:"+System.currentTimeMillis()); } } /** * 获取当前值的线程 */ static class GetThread extends Thread{ private Counter counter; public GetThread(Counter counter) { this.counter = counter; } @Override public void run() { System.out.println("Current:"+ counter.getCurrent()+",trigger time:"+System.currentTimeMillis()); } } }执行结果
Current:0,trigger time:1552487003845 After increase:1,trigger time:1552487008846 After increase:2,trigger time:1552487013848结果分析
从测试结果可以得知
在两个自增线程启动后,获取当前值的线程才启动,但是获取当前值的线程是先被执行完成了。
根据自增线程执行完成的时间戳间隔可以得知,两个自增线程是依次执行的。
从而可以证明
synchronized并不是锁定方法内访问的变量
synchronized锁定的是同一个监视器对象监视的代码
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/73688.html
摘要:本人邮箱欢迎转载转载请注明网址代码已经全部托管有需要的同学自行下载引言多线程如果设计的不合理的话很可能就会出现死锁当两个或者多个线程同事想要去获取共享资源的锁时但每个线程都要等其他线程把他们各自的锁给释放才能继续运行这就是死锁出现死锁必须具 本人邮箱: 欢迎转载,转载请注明网址 http://blog.csdn.net/tianshi_kcogithub: https://github...
摘要:如何维护状态内部维护的读写状态是由位码表示,高位为读状态,表示持有读锁的线程数,低位为写状态,表示写锁的重入次数,状态的改变通过实现,保证同步。写锁降级到读锁有时拥有写锁的线程也希望得到读锁。 ReentrantReadWriteLock 如何保证同步 Java中的可重入读写锁ReentrantReadWriteLock是基于AQS(AbstractQueuedSynchronizer...
摘要:了解自动锁很早就受不了锁的机制了每次都需要在去解锁不仅代码不美观而且很麻烦我想能不能实现加锁之后自动解锁如果是可以利用析构函数实现但就想了想好像可以利用的特性对象只需要实现接口实现自动锁我了解如何利用特性写一个自动锁那么下面我们开始真正 了解自动锁 很早就受不了 java 锁的机制了,每次都需要在 finally 去解锁, 不仅代码不美观,而且很麻烦 我想能不能实现加锁之后自动解锁, ...
摘要:底层是是通过对象,对象有自己的对象头,存储了很多信息,其中一个信息标示是被哪个线程持有。当一个线程执行的代码出现异常时,其所持有的锁会自动释放。 前言 回顾前面: 多线程三分钟就可以入个门了! Thread源码剖析 多线程基础必要知识点!看了学习多线程事半功倍 只有光头才能变强! 本文章主要讲的是Java多线程加锁机制,有两种: Synchronized 显式Lock 不得不唠...
阅读 1996·2021-09-30 09:47
阅读 682·2021-09-22 15:43
阅读 1955·2019-08-30 15:52
阅读 2410·2019-08-30 15:52
阅读 2508·2019-08-30 15:44
阅读 851·2019-08-30 11:10
阅读 3343·2019-08-29 16:21
阅读 3277·2019-08-29 12:19