高级java必会系列二:多线程经常使用的3个关键字:synchronized、ReentrantLock、volatile
系列一讲解了多线程,本章讲解多线程开发中经常使用到的3个关键字synchronized、ReentrantLock、volatile。
一、synchronized
互斥锁,即操作互斥,并发线程过来,串行获得锁,串行执行代码。就像一个房间一把钥匙,一个人进去后,下一个人得等第一个人出来得到钥匙才能进入。如果代码写的不好(A),可能出现死锁!(A得到锁,B等待A释放锁,A不释放,B死锁)
示例代码:
- //修饰静态方法:类级别互斥(只要是房子此方法就互斥)
- public synchronized static void foo1(){
- //do
- }
- //修饰普通方法:对象级别互斥(只有同一间房子此方法互斥)
- public synchronized void foo2(){
- //do
- }
- //修饰代码块
- public void foo3(){
- //类级别互斥
- synchronized(DennyTest.class) {
- //do
- }
- }
- //修饰代码块
- public void foo4(){
- //对象级别互斥
- synchronized(this) {
- //do
- }
- }
需要注意的是,经常使用的是对象级别的互斥,那么特别需要注意是同一个对象的锁。新手经常犯错,都不是同一个对象,当然锁不住。
二、ReentrantLock
可重入锁,和同步锁功能类似,不过需要显示的创建、销毁。特点:
1.ReentrantLock有tryLock方法,如果锁被其他线程持有,返回false,可避免形成死锁。
2.创建时可自定义是否可抢占。
3.ReentrantReadWriteLock,用于读多写少,且读不需要互斥的场景,大大提高性能。
示例代码:
- 1、尝试获取一次
- ReentrantLock lock = new ReentrantLock();
- if (lock.tryLock()) { //得到执行,得不到不执行,就一次。
- try {
- //操作
- } finally {
- lock.unlock();
- }
- }
- 2、同步执行,类似synchronized(也是使用最多的)
- ReentrantLock lock = new ReentrantLock(); //参数默认false,不公平锁:可抢占
- ReentrantLock lock = new ReentrantLock(true); //公平锁:严格按照请求锁的排队顺序获取锁
- lock.lock(); //如果被其它资源锁定,会在此等待锁释放,阻塞
- try {
- //操作
- } finally {
- lock.unlock();
- }
- 3、尝试等待固定时间再次获取
- ReentrantLock lock = new ReentrantLock(true); //公平锁
- try {
- if (lock.tryLock(5, TimeUnit.SECONDS)) {
- //如果已经被lock,尝试等待5s,看是否可以获得锁,如果5s后仍然无法获得锁则返回false
- try {
- //操作
- } finally {
- lock.unlock();
- }
- }
- } catch (InterruptedException e) {
- e.printStackTrace(); //当前线程被中断时(interrupt),会抛InterruptedException
- }
- 4、可中断锁的同步执行
- ReentrantLock lock = new ReentrantLock(true); //公平锁
- lock.lockInterruptibly();
- try {
- //操作
- } catch (InterruptedException e) {
- e.printStackTrace();
- } finally {
- lock.unlock();
- }
三、volatile
volatile,翻译过来是易变的。只保证同一变量在多线程中的可见性。
1)它确保指令重排序时不会把其后面的指令排到内存屏障之前的位置,也不会把前面的指令排到内存屏障的后面;即在执行到内存屏障这句指令时,在它前面的操作已经全部完成;
2)它会强制将对缓存的修改操作立即写入主存;
3)如果是写操作,它会导致其他CPU中对应的缓存行无效。
注意:虽然保证变量是主存数据,但是操作不是原子的,多线程读取到同一个值(是主存的值),同时进行判断或者操作,导致出错。
总结:
可见,synchronized和ReentrantLock是一个级别的,但是volatile只是一个轻量级的关键字。可用场景:
1.状态标记
- volatile boolean inited = false;
- //线程1:
- context = loadContext();
- inited = true;
- //线程2:
- while(!inited ){
- sleep()
- }
- doSomethingwithconfig(context);
2.double check :使用 volatile 关键字来保证多线程下的单例
- public class Singleton {
- private volatile Singleton instance = null;
- public Singleton getInstance() {
- if (instance == null) {
- synchronized(this) {
- if (instance == null) {
- instance = new Singleton();
- }
- }
- }
- return instance;
- }
- }
参考资料:
《深入理解Java虚拟机》
《effective java》
http://www.cnblogs.com/dolphin0520/p/3920373.html
高级java必会系列二:多线程经常使用的3个关键字:synchronized、ReentrantLock、volatile的更多相关文章
- 高级java必会系列一:多线程的简单使用
众所周知,开启线程2种方法:第一是实现Runable接口,第二继承Thread类.(当然内部类也算...)常用的,这里就不再赘述.本章主要分析总结线程池和常用调度类. 一.线程池 1.newCache ...
- 高级java必会系列一:常用线程池和调度类
众所周知,开启线程2种方法:第一是实现Runable接口,第二继承Thread类.(当然内部类也算...)常用的,这里就不再赘述. 一.线程池 1.newCachedThreadPool (1)缓存型 ...
- 高级java必会系列一:zookeeper分布式锁
方案1: 算法思路:利用名称唯一性,加锁操作时,只需要所有客户端一起创建/test/Lock节点,只有一个创建成功,成功者获得锁.解锁时,只需删除/test/Lock节点,其余客户端再次进入竞争创建节 ...
- java多线程系列(五)---synchronized ReentrantLock volatile Atomic 原理分析
java多线程系列(五)---synchronized ReentrantLock volatile Atomic 原理分析 前言:如有不正确的地方,还望指正. 目录 认识cpu.核心与线程 java ...
- 【JAVA编码】 JAVA字符编码系列二:Unicode,ISO-8859,GBK,UTF-8编码及相互转换
http://blog.csdn.net/qinysong/article/details/1179489 这两天抽时间又总结/整理了一下各种编码的实际编码方式,和在Java应用中的使用情况,在这里记 ...
- java基础解析系列(二)---Integer
java基础解析系列(二)---Integer 前言:本系列的主题是平时容易疏忽的知识点,只有基础扎实,在编码的时候才能更注重规范和性能,在出现bug的时候,才能处理更加从容. 目录 java基础解析 ...
- Java多线程之内存可见性和原子性:Synchronized和Volatile的比较
Java多线程之内存可见性和原子性:Synchronized和Volatile的比较 [尊重原创,转载请注明出处]http://blog.csdn.net/guyuealian/article ...
- 高级Java必看的10本书
1.深入理解Java虚拟机:JVM高级特性与最佳实践 本书共分为五大部分,围绕内存管理.执行子系统.程序编译与优化.高效并发等核心主题对JVM进行了全面而深入的分析,深刻揭示了JVM的工作原理. 2. ...
- 系统学习java高并发系列二
转载请注明原创出处,谢谢! 什么是线程? 线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程 ...
随机推荐
- 文本切割软件Replace Pioneer
工作中遇到一些大文本,或者一些文件需要在特定的行切割开的.Replace Pioneer正好用于此的软件. 把一个文本切分不同文本的步骤: 1先把文本数据放到打开
- 【Java EE 学习 36】【struts2】【struts2系统验证】【struts2 ognl值栈】【struts2 ongl标签】【struts2 UI标签】【struts2模型驱动和令牌机制】
一.struts2系统验证 1.基于struts2系统验证的方式实际上就是通过配置xml文件的方式达到验证的目的. 2.实际上系统校验的方法和手工校验的方法在底层的基本实现是相同的.但是使用系统校验的 ...
- 利用python的双向队列(Deque)数据结构实现回文检测的算法
#!/usr/bin/env python # -*- coding: utf-8 -*- # learn <<Problem Solving with Algorithms and Da ...
- Win10 Migrate apps to the Universal Windows Platform (UWP)
https://msdn.microsoft.com/en-us/library/mt148501.aspx
- 【leetcode】Max Points on a Line
Max Points on a Line 题目描述: Given n points on a 2D plane, find the maximum number of points that lie ...
- 通过VS创建简单的WCF服务
http://www.cnblogs.com/artech/archive/2007/09/15/893838.html http://www.topwcftutorials.net/2013/09/ ...
- 移动端使用让图片或者div垂直居中
._limgMIiddle{ /* Firefox */ display:-moz-box; -moz-box-pack:center; -moz-box-align:center; /* Safar ...
- [原创]Centos7 内部常用软件升级计划
GCC 当前系统版本 gcc version 4.8.5 20150623 (Red Hat 4.8.5-4) (GCC)
- Daily Scrum Meeting ——EighthDay
一.Daily Scrum Meeting照片 橙汁参加ICPC未归,周一牛姐去上课,佳恺今天去迎新晚会表演舞台剧了 二.Burndown Chart 今日没有燃掉issues 增添了两个issue ...
- java基础-泛型1
浏览以下内容前,请点击并阅读 声明 泛型的使用能使类型名称作为类或者接口定义中的参数,就像一般的参数一样,使得定义的类型通用性更强. 泛型的优势: 编译具有严格的类型检查 java编译器对于泛型代码的 ...