多线程(三) synchronized
来源:互联网 发布:勿忘我软件下载 编辑:程序博客网 时间:2024/05/22 10:52
说到synchronized可以说是java 多线程第一节课了。每java程序员都知道这个关键字。这里就这个关键字的原理和使用在介绍一次,一方面巩固理解,一方面和大家讨论一下。
这个关键词使用起来很简单,就是将代码段,或者方法,加锁实现串行执行,可是锁是什么?这个就是一个初学者常见的坑。
锁有3种:1.成员属性锁。2,对象锁(也就是this关键字;或者方法加上synchronized,静态方法除外)3.类锁(Test.class;静态方法加上synchronize也是)。
什么时候用什么锁,只要保持一个原则,可见原则,解释一下,就是你同步的代码中是否看到的都是一个锁。
比如说:静态方法,就要用类锁。因为静态方法所属于类。对象还不存在,不能用对象锁。
普通方法,可以用对象锁。如果是成员属性锁,那么这个必须在方法调用前初始化,同时不能改变。
这是时候就有一个疑问,我都用类锁,所有人都可以看见都是一个,不就行了吗。理论上使可行的,但实际行不通。因为锁的方法,串行的,其他人都要等待,这会让你的程序只有一个用户可以访问,其他人等着。(在实际中通常行不通,除非你就是想玩用户)
有了多用户的需求,我们就尽量减少同步时间,就产生了以下原则:
1.尽量使用低阶别的锁,成员属性锁<对象锁<类锁。
2.尽量使用同步块代替同步方法,减少同步代码。
3 耗时的代码进行不要在同步块中。(这里强调一下,不要把sql放到同步块中,你可能想这样就不会发生数据不一致问题,但是如果是集群呢,数据库还要靠事务保证,不是程序同步块)
下面用代码说一下使用:
package com.ldh.syn;public class SynTest1 {private int i = 0;public synchronized void run(){System.out.println(++i);try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}}public static void main(String[] args) {final SynTest1 t = new SynTest1();for(int i=0;i<20;i++){new Thread(()->{t.run();}).start();;}}}
这段代码实现一次计数,计数后休息3秒,模仿慢代码执行。20次计数就要花费60s时间。所以尽量减少同步块大小。
package com.ldh.syn;import java.util.Date;public class SynTest extends Thread {private static int i = 0;private Date startDate ;public SynTest(Date startDate) {this.startDate = startDate;}@Overridepublic synchronized void run() {System.out.println(++i);try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}Date date = new Date();System.out.println(date.getTime()-startDate.getTime());}public static void main(String[] args) {final Date startDate = new Date();for(int i=0;i<20;i++){new SynTest(startDate).start();}}}这段代码看上去没什么问题,其实是错的并不能实现同步功能,你运行的时候可会出现打印1-20 。那是因为start(),需要时间,先启动的一定先执行。
错误的原因是,每次都new 一个 synTest的对象。普通同步方法是对象锁,观察的不是一个对象(锁),所以不能实现同步效果。
简单说一下底层实现:
synchronize 同步后,会发生阻塞,阻塞的线程进入阻塞池(相当于一个队列),线程执行完成后,队列中的线程进行抢夺,抢到时间片的进行执行代码。
jdk1.8中,jvm开发人员发现其实大部分时候不会发生阻塞强占,都是一个线程在自己抢夺自己(你可能问自己强自己为什么,因为分时操作系统,一个时间片,你不一定能执行完同步块中的代码。)这时候设计了3中所结构: 偏向锁,轻量级锁,重量级锁。
偏向锁,具有自己的引用,如果多个线程冲突,那么就自动让自己通过。
轻量级锁,如果多个线程同时进行强占,那么将偏向锁升级为轻量级锁。这时候会有自旋,就是不断的抢夺。
重量级锁,如果有更多线程同时进行强占,将轻量级锁升级为重量级锁。大家进行等待,可以减少自旋。
总结一下,以上3种锁为了更快的让一个线程执行代码,减少阻塞所带来的等待时间。如果是单线程无冲突的情况下,加锁比不加锁效率已经差距不大了。
参考文章: http://ifeve.com/java-synchronized/
- 多线程(三) synchronized
- 多线程(三) synchronized关键字
- java多线程(三)Synchronized
- 多线程学习三(synchronized和Lock)
- 多线程系列(三)---synchronized其他概念
- 多线程并发编程(三):多线程同步互斥Synchronized
- JAVA学习笔记--多线程(三)synchronized实现线程同步
- 译 -- Java 并发编程(多线程)三 | Semaphore | ThreadLocal | synchronized
- Java多线程基础篇三------synchronized
- 多线程(三)——多线程安全问题之同步代码块(Synchronized)
- synchronized详解(三)
- 多线程(二):synchronized 关键字
- 多线程之synchronized(this)
- Java多线程总结笔记(三)—— 同步和锁机制、synchronized
- JAVA多线程(五)用lock、synchronized、阻塞队列三种方法实现生产者消费者模式
- synchronized多线程
- 多线程-synchronized
- JAVA Synchronized 详解(三)
- UESTC 1642 老当益壮, 宁移白首之心?
- PAT(B)-1063. 计算谱半径(20)
- javascript--面向对象(三)原型对象存在的问题及组合组合使用原型和构造函数
- 不想学挖掘机的厨师不是好程序员!
- SQL数据库基本操作
- 多线程(三) synchronized
- linux下安装scipy
- 笔记本Ubuntu系统 开启Wifi
- [LeetCode] 290. Word Pattern
- 数组的应用举例及二维数组的声明使用
- libvirt Java API用法连载之Ubuntu16.04安装QEMU与libvirt(二)
- vgg16构造模型图
- 《C++对象模型》读书笔记
- java面试全集(上)