为什么80%的码农都做不了架构师?>>>   

volatile 

     Volatile 变量具有 synchronized 的可见性特性,但是不具备原子特性。这就是说线程能够自动发现 volatile 变量的最新值。在理解volatile作用时候,我们先看看jvm的内存模型。

Java内存模型规定,对于多个线程共享的变量,存储在主内存当中,每个线程都有自己独立的工作内存,线程只能访问自己的工作内存,不可以访问其它线程的工作内存。工作内存中保存了主内存共享变量的副本,线程要操作这些共享变量,只能通过操作工作内存中的副本来实现,操作完毕之后再同步回到主内存当中。

一个变量被定义为volatile,那说明这个变量是易变的。如果一个线程修改了这个变量,那这个线程将通知其他线程这个变量已做修改,工作内存保持的变量副本时效,必须重新从共享内存读取这个变量的最新值,因此,被volatile非常适合做状态标识。

public class Volatile {private volatile static boolean flag = true;public static void work() {while (flag) {System.out.println("=============");}}public static void stop() {flag = false;System.out.println("----stop work----");}public static void main(String[] args) {new Thread(new Runnable() {public void run() {work();}}).start();new Thread(new Runnable() {public void run() {try {Thread.sleep(100l);} catch (InterruptedException e) {}stop();}}).start();}
}

可以看见线程马上结束了自己的工作,但是我们如果不用volatile修饰flag,还是发现线程也马上停止了在控制台的打印。HotSpot编译器在server模式和client模式编译不同, 在client模式下,多线程读取变量时,都会直接从主内存中去读取,不会保存在工作内存中,所有加不加volatile效果一样,而server模式下,则对代码做了优化。而eclipse中默认的启动模式client。


ReetrantLock

     (画了一张不知道是什么图的图),图上我们可以看出,ReetrantLock有有属性Sync sync,FairSync和NonFairSync是Sync的两个子类,Sync继承自AQS(AbstractQueuedSynchronizer)。

   

    很明显,ReetrantLock实现了公平锁和非公平锁。通过源码我们可以看出ReetrantLock默认为非公平锁,并且提供了一个boolean参数的构造函数,true为公平锁,false为非公平锁。

 public ReentrantLock(){sync = new NonfairSync();}public ReentrantLock(boolean flag){sync = ((Sync) (flag ? ((Sync) (new FairSync())) : ((Sync) (new NonfairSync()))));}

现在我们来看看你ReetrantLock.lock()到底干了什么?

 //FairSync:final void lock(){acquire(1);}//NonFairSync:final void lock(){if(compareAndSetState(0, 1))setExclusiveOwnerThread(Thread.currentThread());elseacquire(1);}//acquire(int i):public final void acquire(int i){if(!tryAcquire(i) && acquireQueued(addWaiter(Node.EXCLUSIVE), i))selfInterrupt();}

非公平锁一开始尝试检查state的值,如果是0就通过CAS看是否能成功置成1,操作如果成功,那么该线程获得锁,而公平锁并没有,这也就是公平和非公平的区别。如果非公平锁对state的CAS没有成功,则和公平锁一样acquire()。

 //FairSync:protected final boolean tryAcquire(int i){Thread thread = Thread.currentThread();int j = getState();if(j == 0){if(!hasQueuedPredecessors() && compareAndSetState(0, i)){setExclusiveOwnerThread(thread);return true;}} elseif(thread == getExclusiveOwnerThread()){int k = j + i;if(k < 0){throw new Error("Maximum lock count exceeded");} else{setState(k);return true;}}return false;}//NonFairSync:final boolean nonfairTryAcquire(int i){Thread thread = Thread.currentThread();int j = getState();if(j == 0){if(compareAndSetState(0, i)){setExclusiveOwnerThread(thread);return true;}} elseif(thread == getExclusiveOwnerThread()){int k = j + i;if(k < 0){throw new Error("Maximum lock count exceeded");} else{setState(k);return true;}}return false;}

同样在tryAcquire中,公平锁在state=0的情况下看了看sync队列中有没有人排在前面(确实是挺公平的),而非公平锁完全是不管这条件的,我们再来看看acquireQueued(addWaiter(Node.EXCLUSIVE), i),addWaiter是把线程包装成Node,这里就不贴出来了。

final boolean acquireQueued(final Node node, int arg) {boolean failed = true;try {boolean interrupted = false;for (;;) {final Node p = node.predecessor();//如果当前的节点是head说明他是队列中第一个“有效的”节点,因此尝试获取if (p == head &&tryAcquire(arg)) {setHead(node);p.next = null;failed = false;return interrupted;}//否则,检查前一个节点的状态为,看当前获取锁失败的线程是否需要挂起。//如果需要,借助JUC包下的LockSopport类的静态方法Park挂起当前线程。if (shouldParkAfterFailedAcquire(p, node)&&parkAndCheckInterrupt()) interrupted = true;}} finally {//如果有异常if (failed)// 取消请求,对应到队列操作,就是将当前节点从队列中移除。 cancelAcquire(node);}
}

到此为止,一个线程对于锁的一次竞争才告一段落,结果又两种,要么成功获取到锁(不用进入到AQS队列中),要么获取失败被挂起,等待下次唤醒后继续循环尝试获取锁,值得注意的是,AQS的队列为FIFO队列,所以,每次及时被CPU假唤醒,且当前线程不是出在头节点的位置,也是会被挂起的。(为了防止篇幅过长,AQS中的condition和node将在下篇讲)。


那么问题来了,sychronized和ReentranLock各自要在什么场合用呢?下面贴一下各大博客的总结吧

synchronized是托管给JVM执行的,而lock是java写的控制锁的代码。在Java1.5中,synchronize是性能低效的。因为这是一个重量级操作,需要调用操作接口,导致有可能加锁消耗的系统时间比加锁以外的操作还多。相比之下使用Java提供的Lock对象,性能更高一些。但是到了Java1.6,发生了变化。synchronize在语义上很清晰,可以进行很多优化,有适应自旋,锁消除,锁粗化,轻量级锁,偏向锁等等。导致在Java1.6上synchronize的性能并不比Lock差。官方也表示,他们也更支持synchronize,在未来的版本中还有优化余地。

synchronized原语和ReentrantLock在一般情况下没有什么区别,但是在非常复杂的同步应用中,请考虑使用ReentrantLock,特别是遇到下面2种需求的时候。
     1.某个线程在等待一个锁的控制权时需要中断
     2.多个条件变量或者锁投票
     3.时间锁等候或者无块机构锁

转载于:https://my.oschina.net/chener/blog/478640

synchronized,ReetrantLock与volatile(二)相关推荐

  1. 已经有了synchronized为什么需要volatile

    文章目录 1.volatile和synchronized特点 2.volatile和synchronized的区别 3.synchronized 问题 3.1 有性能损耗 3.2 产生阻塞 4. vo ...

  2. Java多线程基础-6:线程安全问题及解决措施,synchronized关键字与volatile关键字

    线程安全问题是多线程编程中最典型的一类问题之一.如果多线程环境下代码运行的结果是符合我们预期的,即该结果正是在单线程环境中应该出现的结果,则说这个程序是线程安全的. 通俗来说,线程不安全指的就是某一代 ...

  3. java和线程相关的关键字有哪些_Java中有哪些机制来保证线程安全?synchronized关键字和volatile关键字...

    想要解决线程安全问题,首先要知道为什么会造成线程不安全? 在单线程中,我们从来没有提到个线程安全问题,线程安全问题是只出现在多线程中的一个问题.因为多线程情况下有共享数据,每个线程都共享这些数据并对这 ...

  4. linux 原子整数操作详解 及 volatile (二)

    2019独角兽企业重金招聘Python工程师标准>>> 原子操作,顾名思义,就是说像原子一样不可再细分不可被中途打断.一个操作是原子操作,意思就是说这个操作是以原子的方式被执行,要一 ...

  5. java synchronized 卖票_(二)java多线程之synchronized

    引言 现在,让我们来考虑一个问题,如果要让多个线程来访问同一份数据,会发生什么现象呢?比如12306的火车售票系统,比如银行的存取款系统等等.都可以会出现多线程访问同一个数据的情况.让我们先模拟写一个 ...

  6. java 轻量级同步volatile关键字简介与可见性有序性与synchronized区别 多线程中篇(十二)...

    概念 JMM规范解决了线程安全的问题,主要三个方面:原子性.可见性.有序性,借助于synchronized关键字体现,可以有效地保障线程安全(前提是你正确运用) 之前说过,这三个特性并不一定需要全部同 ...

  7. JAVA多线程之volatile 与 synchronized 的比较

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 来源:hapjin cnblogs.com/hapjin/p/54 ...

  8. 原创 | 既生synchronized,何生volatile?!

    △Hollis, 一个对Coding有着独特追求的人△ 这是Hollis的第 225篇原创分享 作者 l Hollis 来源 l Hollis(ID:hollischuang) 在我的博客和公众号中, ...

  9. 用多线程模拟5000人抢1000张票, 测试volatile, synchronized, vector的效用

    想要模拟的情况: 1. 总共出票5轮,每次出票200张,本轮票售完后才出下一轮的票,共出票1000张,(票号1-1000),每张票30元,最后商家收到30000元,商家准备票的时候不允许买家订票 2. ...

最新文章

  1. c枚举类型enum例题_一篇文章让你详细了解Java中Enum枚举类的使用
  2. Python图像处理库:PIL中Image,ImageDraw等基本模块介绍
  3. java标点符号用什么意思_java怎么统计字符串内的标点符号?
  4. 分布式会话拦截器2 - 会话判断
  5. CADENCE ORCAD原理图导出FPGA UCF的方法
  6. Leetcode47: Palindrome Linked List
  7. codeforces1167 E. Range Deleting(双指针)
  8. “跟童老师学编程”专栏目录
  9. 回头再说-006 时间音乐
  10. 数据--第26课 - 排序的概念及分类
  11. 2018_09_25_参加医学人工智能大会的个人思考
  12. angular6之Http服务
  13. python语言程序设计教程课后答案刘卫国_Visual FoxPro程序设计教程(主编:刘卫国 第三版)1-5课后答案...
  14. 基于Java的2048小游戏设计
  15. 怎样编辑pdf文件?手把手教你如何使用PDF编辑器
  16. px和毫米的换算_关于PX像素、PT点数、CM厘米、MM毫米之间的换算
  17. 冬奥探秘:那些隐匿在冬奥中的“绿科技”
  18. win10计算机网络共享设置密码,Win10使用技巧:给共享文件夹添加密码
  19. 微信小程序开发抽取HTML中数据的最快方法是正则表达式,而不是循环
  20. 年薪40W+,2018年程序员如何跳出35岁“失业”怪圈?

热门文章

  1. 【Docker系列教程之一】docker入门
  2. linux下用户切换
  3. 浅述几年建站SEO之路的失败与反思
  4. C#父类与子类(多态性)
  5. 摘自网络--浅析UpdatePanel的partial render原理
  6. 使用window.createPopup创建无限级跨帧下拉菜单
  7. qt-制作生成dll动态链接库实例
  8. python bind_Python bind-允许同时按下多个键
  9. tcp 组播_华为组播理论知识详解(二)
  10. 关于低代码自定义表单的思路和想法