多线程、锁,可重入,同步,原子性,可见性,非阻塞算法
来源:互联网 发布:哈弗福德文理学院 知乎 编辑:程序博客网 时间:2024/05/20 03:47
问题1 什么是Re-entrant Lock
锁的acquire是per thread 的, 而不是per call的,也就是同一个线程再次申请已经获得的锁,直接成功返回。如果是非re-entrant的锁,一个线程试图获取已经获得的锁会死锁,因为当前线程会挂起,没有机会release锁
synchronized的锁和 ReentrantLock都是 Re-entrant Lock
问题2:java已经有了synchronized,为什么还要在jdk1.5中加入Lock系列?
ReentrantLock 和 synchronized有相同的语义,但是有更高的性能,ReentrantLock 使用原子变量来维护等待锁定的线程队列。
synchronized获取锁的时候只能一直等,没有超时机制,也不能被打断,而且锁的获取和释放必须在一个方法内
而ReentrantLock的lock方法和synchronized是等同语义的,还可以通过tryLock等方法有多种选择,并且以接口和类的形式而不是语言feature的形式存在,更好扩展。
public interface Lock { void lock(); void lockInterruptibly() throws InterruptedException; boolean tryLock(); boolean tryLock(long time, TimeUnit unit) throws InterruptedException; void unlock(); Condition newCondition();}Lock的确缺点是必须在finally块中 unlock
问题3:AtomicInteger 主要解决原子性,那可见性呢?需要用volatile声明吗?
AtomicInteger 内部维护的那个int值是用volatile声明的,所以也AtomicInteger也保证了可见性,不需要再用volatile声明
注意:可见性保证只有两个办法,就是synchronized和 volatile
问题4:一个int 成员变量,一个方法赋值,一个方法读值,多线程环境下,需要同步吗?
需要同步,或者用volatile,并且读操作也需要同步。赋值和读值是原子的,但是依旧有可见性问题,否则也许读方法永远都不到最新的值。为什么数据库查询也需要事务?也是可见性问题。
问题5:用最小的开销实现实现计数器
@ThreadSafepublic class CheesyCounter { // Employs the cheap read-write lock trick // All mutative operations MUST be done with the 'this' lock held @GuardedBy("this") private volatile int value; public int getValue() { return value; } public synchronized int increment() { return ++value; }}
++value是非原子操作(典型的 读取-修改-写回)用synchronized 保证原子性(也可以用ReentrantLock) ,getValue是原子的,可见性问题由volatile保证了。假如不用volatile那个简单的读取也要用锁
问题6 volatile的经典应用场景
1)对变量的操作是原子的,(注意原子操作只有赋值和读取,即“=”操作符,++value不是)
2)只有一个线程写,这样就不会产生更新丢失问题,
具体的,最经典的应用就是flag,即第一种场景。 比如一个死循环的服务线程,通过外部线程设置 exit 的flag决定是否退出。
问题7 用ReentrantLock代替synchronized后, 需要用wait, notify的时候怎么办?
众所周知,wait和notify必须放在synchronized块里,现在用了Lock了怎么办?答案是Lock的Condition,也就是用了不需要用Object.wait()了
问题8 锁的等待队列,是先申请的线程先获取吗?
ReentrantLock的构造函数有一个参数,指定这个锁是fair的还是unfair的,fair的意思是说按申请锁的先后顺序排队,先到先得,而unfair的锁不保证这一点。默认是unfair的。 而且,内置的synchronized锁是unfair的,也就是其实先申请锁的线程不一定先执行!
fair的锁比较慢,几种并发模式的性能比较 Fair ReentrantLock < synchronized < Unfair ReentrantLock < 非阻塞算法
问题9 非阻塞算法原理
一般基于CAS, (campare and set/swap),用一个while循环,先读取old value, 然后计算新值,在更新的时候看target 变量的值是否还是oldvalue,如果是,说明没有别的线程干扰,执行更新,否则有别的线程更新过,while回去重新来一遍。注意这里的“看target 变量是否还是oldvalue并且更新”是一个原子操作CAS。
public class NonblockingCounter { private AtomicInteger value; public int getValue() { return value.get(); } public int increment() { int v; do { v = value.get(); while (!value.compareAndSet(v, v + 1)); return v + 1; }}
无锁堆栈
class ConcurrentStack<E> { AtomicReference<Node> head = new AtomicReference<Node>(); public void push(E item) { Node newHead = new Node(item); Node oldHead; do { oldHead = head.get(); newHead.next = oldHead; } while (!head.compareAndSet(oldHead, newHead)); } public E pop() { Node oldHead; Node newHead; do { oldHead = head.get(); if (oldHead == null) return null; newHead = oldHead.next; } while (!head.compareAndSet(oldHead,newHead)); return oldHead.item; } class Node { final E item; Node next; public Node(E item) { this.item = item; } }}
- 多线程、锁,可重入,同步,原子性,可见性,非阻塞算法
- 多线程原子性、可见性、可排序
- 多线程:原子性与非原子性
- 原子变量和非阻塞同步机制
- 非阻塞同步算法
- 多线程并发编程之原子变量与非阻塞同步机制
- Java同步——可见性和原子性
- java多线程初步-原子性可见性hanppens-before原则
- 关于多线程(三)---可见性与原子性
- Java多线程中的内存可见性与原子性分析
- Java多线程 之 原子性与可见性(八)
- java 多线程开发中的原子性,与可见性
- Java多线程 之 原子性与可见性(八)
- 多线程之原子性,可见性,有序性,并发问题解决
- java多线程之共享变量的可见性、原子性
- 多线程之内存可见性和原子性
- Java的多线程之同步篇三:同步阻塞、监视器、volatile、final、原子性、线程局部变量、锁测试与超时、读写锁
- 尝试Java加锁新思路:原子变量和非阻塞同步算法
- eclipse 设置系统变量和运行参数
- windows下安装nginx
- 解决Struts中文乱码问题总结
- ST芯片的引脚复用功能和重映射功能
- SSH框架
- 多线程、锁,可重入,同步,原子性,可见性,非阻塞算法
- 在linux上使用yum安装JDK
- mongodb添加用户密码并进行配置
- [转]MySQL 调优/优化的总结100个建议
- 7 天玩转 ASP.NET MVC — 第 1 天
- 大数据分析之Spark初步——从安装到Demo
- Unity3D自带例子AngryBots的分析
- cocos2d-x学习篇之网络(http)篇
- MySQL Study之--MySQL下图形工具的使用(MySQL Administrator)