【SharingObjects】ThreadLocal
描述
该类提供了线程局部(thread-local)变量。这些变量不同于它们的普通对应物,因为访问某个变量(通过其get或set方法)的每个线程都有自己的局部变量,它独立于变量的初始化副本。ThreadLocal实例通常是类中的private static字段,它们希望将状态与某一个线程(例如,用户ID或事物ID)相关联。
场景适用于无状态,副本变量独立后不影响业务逻辑的高并发场景。Hibernate的session获取场景
123456789101112131415161718192021private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();//获取Sessionpublic static Session getCurrentSession(){ Session session = threadLocal.get(); //判断Session是否为空,如果为空,将创建一个session,并设置到本地线程变量中 try ...
【锁】Condition接口分析
引言Condition是用来代替传统Object中的wait()和notify()实现线程间的协作,Condition的await()和signal()用于处理线程间协作更加安全与高效,JAVA中的阻塞队列就是用Condision实现。Condition的使用必须在锁定与解锁直接使用,且只能通过lock.newCondition()获取。
使用例子:假设有一个有界的缓冲区,它支持put和take方法。如果在空缓冲区上尝试take,那么线程将阻塞,直到缓冲区中有数据可用为止;如果在一个数据已满的缓冲区上尝试put,那么线程将阻塞,直到空间可用为止。我们希望在单独的等待集中继续等待put线程和take线程,这样我们就可以在缓冲区中的数据或空间可用时只通知单个线程。这可以使用两个Condition实例来实现。
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152//有界缓冲 class BoundedBuffer { //重入锁 fin ...
【锁】ReentrantReadWriteLock之读写锁公平性体现源码分析
ReentrantReadWriteLock的公平性体现在Sync的两个子类NonfairSync和FairSync重写的Sync中的两个方法:
1234567891011121314151617/** * Returns true if the current thread, when trying to acquire * the read lock, and otherwise eligible to do so, should block * because of policy for overtaking other waiting threads. * 如果当前线程在尝试获取读锁时阻塞,并且由于策略原因无法超过其他等待的线程, * 因此有资格阻塞读锁,则返回true。 */ abstract boolean readerShouldBlock(); /** * Returns true if the current thread, wh ...
【锁】ReentrantLock之获取锁时公平性的体现与锁的释放
引言公平锁实现了先进先出的公平性,但是由于来一个线程就加入队列中,往往都需要阻塞,再由阻塞变为运行,这种上下文切换非常资源。非公平锁由于允许插队,所以上下文切换少,能保证的大的吞吐量,但是容易出现饥饿问题。
查看ReentrantLock源码,其内部有三个重要的内部类:Sync继承自AbstractQueueSynchronizer同步器,这个锁的同步操作由这个Sync来保证。NofairSync非公平同步器,继承Sync,在同步的基础上,保证线程获取锁是非公平的。FairSync公平同步器,继承Sync,公平锁的体现。
ReentrantLock默认初始化为非公平锁。
在执行ReentrantLock的Lock方法的时候,会调用Sync的Lock方法,最后由NofairSync或者FairSync实现。
123456789 public void lock() { sync.lock(); }/** * Performs {@link Lock#lock}. The main reason for subclassing ...
【锁】ReadWriteLock之读写锁在获取锁与释放锁分析
引言由ReentrantReadWriteLock源码可知,读锁与写锁共同使用了一个Sync同步器,即使用了同一个同步队列。
获取锁获取读锁123public void lock() { sync.acquireShared(1); }
直接调用了同步器的共享锁。AQS中的acquireShared方法会回调Sync的tryAcquireShared(int unused)方法。
1234public final void acquireShared(int arg) { if (tryAcquireShared(arg) < 0) doAcquireShared(arg); }
tryAcquireShared方法相对来说就比较复杂了,连蒙带猜写的注释:
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596 ...
【锁】ReadWriteLock之简单分析
引言ReadWriteLock包含一对关联的锁,一个用于只读,另一个用于写。readLock只要没有写者,可以同时被多个读线程所有, writeLock是独占的。writeLock操作的内存同步效果对关联的readLock也有效读写锁允许在访问共享数据时具有比互斥锁所允许的更高级别的并发性,因为虽然写锁每次只有一个线程,但是只有写线程可以修改共享的数据,在许多情况下,任意数量的读线程都可以并发地读取数据。但是有个前提:这种并发性的增加只有在多处理器上才能完全实现,而且只有在共享数据的访问模式合适时才能实现。
读写锁ReadWriteLock123456789101112131415public interface ReadWriteLock { /** * Returns the lock used for reading. * * @return the lock used for reading */ Lock readLock(); /** * Returns the lock used for writing. ...
【锁】分类
公平锁/非公平锁公平锁是指多线程按照申请锁的顺序来获取锁,非公平锁指多个线程获取锁的顺序不是按照申请锁的顺序,有可能造成优先级反转或者饥饿现象,非公平锁的优点在于吞吐量比公平锁大,ReentrantLock默认非公平锁,可通过构造函数选择公平锁,Synchronized是非公平锁。
可重入锁可重入锁指在一个线程在外层方法获取锁的时候,在进入内层方法会自动获取锁,ReentrantLock与Synchronized都是可重入的。
独享锁/共享锁独享锁是指一个锁只能一个线程独有,共享锁指一个锁可被多个线程共享,对于ReadWriteLock,读锁是共享锁,写锁是独享所。
互斥锁/读写锁独享锁/共享锁是一种广义的说法,互斥锁/读写锁是其具体实现。
乐观锁/悲观锁乐观锁与悲观锁是看待同步的角度不同,乐观锁认为对于同一个数据的修改操作,是不会有竞争的,会尝试更新,如果失败,不断重试。悲观锁与此相反,直接获取锁,之后再操作,最后释放锁。
分段锁分段锁是一种设计思想,通过将一个整体分割成小块,在每个小块上加锁,提高并发。
偏向锁/ ...
【AQS】共享锁的获取
引言共享锁的获取与独占锁很像,他们的区别就是当独占锁已经被某个线程持有时,其他线程只能等待它被释放后,才能去争锁,并且同一时刻只有一个线程能争锁成功。而共享锁再获取锁之后,其他线程就可以去争锁,所以会有一个锁被多个线程持有的状态。
即:独占锁只有释放锁之后唤醒同步队列后面的节点,共享锁在获取到锁和释放锁之后都会唤醒同步队列后面的节点。
AQS中共享锁的获取逻辑代码:
123456789101112131415161718192021/** * Acquires in shared mode, ignoring interrupts. Implemented by * first invoking at least once {@link #tryAcquireShared}, * returning on success. Otherwise the thread is queued, possibly * repeatedly blocking and unblocking, invoking {@link * ...
【AQS】Condition接口的实现
同步队列与条件队列sync queue
同步队列是双向链表,使用prev和next来连接节点,nextWaiter属性只是一个标志作用,共享锁模式下使用。入队时没有锁 -> 在队列中争锁 -> 离开队列时获得了锁
condition queue
条件队列是用nextWaiter连接节点的单链表。其waitStatus属性中只关注CONDITION,表示线程处于正常的等待状态。入队时持有锁 -> 在队列中释放锁 -> 离开队列时没有锁 -> 转移到sync queue
同步队列与条件队列的联系
当调用某个条件队列的signal方法时,会将某个或所有等待在这个条件队列中的线程唤醒,被唤醒的线程和普通线程一样需要去争锁,如果没有抢到,则要被加到等待锁的sync queue中去,此时节点就从condition queue中被转移到sync queue中。
CondtionObject源码分析核心属性12345678910/** * First node of condition queue. * 首哨兵 */ ...
【AQS】共享锁的释放
引言共享锁的释放的主要方法doReleaseShared()已经在共享所的获取中简单的分析了一下,可见共享锁触发唤醒后记节点的行为有两处:第一,当前节点成功获取共享锁后,第二,当前节点释放共享锁后。下面分析共享锁释放的主要逻辑代码:
123456789101112131415161718/** * Releases in shared mode. Implemented by unblocking one or more * threads if {@link #tryReleaseShared} returns true. * * @param arg the release argument. This value is conveyed to * {@link #tryReleaseShared} but is otherwise uninterpreted * and can represent anything you like. * @retur ...