ThinkSSL🔒 一键申购 5分钟快速签发 30天无理由退款 购买更放心 广告
!欢迎关注我的公众号: ![我的公众号](https://markdown-1258186581.cos.ap-shanghai.myqcloud.com/20190606104746.png) [toc] # Java 中的 Synchronized 关键字 synchronized是Java中的关键字,是一种同步锁。它修饰的对象有以下几种: 1. 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象; 2. 修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象; 3. 修改一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象; 4. 修改一个类,其作用的范围是synchronized后面括号括起来的部分,作用主的对象是这个类的所有对象。 ### 修饰一个代码块 一个线程访问一个对象中的synchronized(this)同步代码块时,其他试图访问该对象的线程将被阻塞。 多个线程访问**不同对象**的时候,执行到这个代码块的时候,均会执行该方法,不会发生方法上锁的情况。 ![](https://markdown-1258186581.cos.ap-shanghai.myqcloud.com/20190610110614.png) #### 多个线程访问同个对象的一个方法 ![](https://markdown-1258186581.cos.ap-shanghai.myqcloud.com/20190610134825.png) 结果:谁拿到锁谁执行,没拿到的等待 ![](https://markdown-1258186581.cos.ap-shanghai.myqcloud.com/20190610134911.png) #### 多个线程访问多个对象的一个方法 ![](https://markdown-1258186581.cos.ap-shanghai.myqcloud.com/20190610134952.png) 结果:多个线程各自访问各自拥有对象的方法: ![](https://markdown-1258186581.cos.ap-shanghai.myqcloud.com/20190610135040.png) #### Synchronized 锁一个明确的对象 新建卖票类,sell 方法卖出一张票减一,addTicket 方法补一张票的库存。 ![](https://markdown-1258186581.cos.ap-shanghai.myqcloud.com/20190610140251.png) 新建卖票线程,在 run 方法里面每卖一张票就补一张票的库存。 ![](https://markdown-1258186581.cos.ap-shanghai.myqcloud.com/20190610140353.png) 最后开启五个卖票线程去卖票: ![](https://markdown-1258186581.cos.ap-shanghai.myqcloud.com/20190610140504.png) 结果: ![](https://markdown-1258186581.cos.ap-shanghai.myqcloud.com/20190610140542.png) 可以看到这里的并不是 从 A B C D E 依次执行的,因为谁拿到执行权就谁去执行。 #### 没有明确的锁,只是为了给一块代码加上同步 ![](https://markdown-1258186581.cos.ap-shanghai.myqcloud.com/20190610140832.png) 说明:零长度的byte数组对象创建起来将比任何对象都经济――查看编译后的字节码:生成零长度的byte[]对象只需3条操作码,而Object lock = new Object()则需要7行操作码 ### 修饰一个方法 Synchronized 修饰一个方法的格式是 ```java public Synchronized void run(){ // code } ``` Synchronized 关键字修饰的是整个函数里面的内容,当相同对象在多线程访问的 run 方法的时候,由于被 Synchronized 关键字修饰,不能同时访问。 这种写法等价于修饰代码块的这种写法: ```java public void run(){ Synchronized(this){ // code } } ``` 两种写法的 code 都是可以互斥访问的。 Synchronized 修饰方法的注意事项: 1. Synchronized 修饰方法不能被子类继承 2. 接口中不能写 Synchronized 3. 构造方法不能使用synchronized关键字,但可以使用synchronized代码块来进行同步。 ### 修饰一个静态的方法 这种情况也是针对于所有对象的这个方法,当多个线程访问这个代码块的时候,均会进行资源竞争的情况,谁拿到锁谁执行,没拿到的等待。 使用方法: ```java public synchronized static void method() { // code } ``` Synchronized 作用在静态方法中,相当于给整个类加了锁,不管是类的哪个对象访问这个方法的时候,都会竞争锁的资源. 需要注意的是:对其他没加 Synchronized 的方法没有影响。 #### 加上 Synchronized 关键字 ![](https://markdown-1258186581.cos.ap-shanghai.myqcloud.com/20190610132600.png) 结果: ![](https://markdown-1258186581.cos.ap-shanghai.myqcloud.com/20190610132650.png) #### 不加 Synchronized ![](https://markdown-1258186581.cos.ap-shanghai.myqcloud.com/20190610132727.png) 结果: ![](https://markdown-1258186581.cos.ap-shanghai.myqcloud.com/20190610132752.png) ### 修饰一个类 这种情况也是针对于所有对象的这个方法,当多个线程访问这个代码块的时候,均会进行资源竞争的情况,谁拿到锁谁执行,没拿到的等待。 使用方法: ```java class ClassName { public void method() { synchronized(ClassName.class) { // todo } } } ``` #### 使用 synchronized(ClassName.class) ![](https://markdown-1258186581.cos.ap-shanghai.myqcloud.com/20190610133412.png) 结果:顺序执行,A 获得锁以后,B 只能等待 A 释放 ![](https://markdown-1258186581.cos.ap-shanghai.myqcloud.com/20190610133453.png) #### 不使用 synchronized(ClassName.class) ![](https://markdown-1258186581.cos.ap-shanghai.myqcloud.com/20190610133547.png) 结果:谁竞争到执行权,执行谁 ![](https://markdown-1258186581.cos.ap-shanghai.myqcloud.com/20190610133620.png) ## 总结: 1. 无论synchronized关键字加在方法上还是对象上,如果它作用的对象是非静态的,则它取得的锁是对象;如果synchronized作用的对象是一个静态方法或一个类,则它取得的锁是对类,该类所有的对象同一把锁。 2. 每个对象只有一个锁(lock)与之相关联,谁拿到这个锁谁就可以运行它所控制的那段代码。 3. 实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。