JAVA中的锁一直是一块比较难理解的地方。 锁涉及到便是多线程。
下面是多线程编程中需要注意的地方
原子性(Synchronized, Lock)即一个操作或者多个操作 要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行。 有
序性(Volatile,Synchronized, Lock)即程序执行的顺序按照代码的先后顺序执行。
可见性(Volatile,Synchronized,Lock)指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。
特此,记下来,怕自己忘了。
AQS:AbstractQueuedSynchronizer队列同步器,它用一个32位的整形来表示目前线程的同步状态, 可以通过以下几个方法来读取,设置和修改这个状态:getState(),setState(),compareAndSetState().
当然,这个compareAndSetState()使用了CAS操作。
另外再说一句: AbstractQueuedSynchronizer 是个抽象类,如果要使用他对临界资源的获取和控制,就要实现两个比较关键的方法tryAcquire和tryRelease。
另外还提供了大量的同步操作,而且用户还可以在此类的基础上自定义自己的同步类。其设计目标主要有两点:
1、提高可扩展性,用户可以自定义自己的同步类
2、最大限度地提高吞吐量,提供自定义公平策略 毕竟ReentrantLock中的抽象内部类大多数都继承与AbstractQueuedSynchronizer; 此节重点在于:一个管理同步关系的32位整形,以及控制这个整形并发下的更改操作,强大的CAS。以及涉及到的模版方法模式。
队列: AQS对于没有获取到锁的任务,有一个FIFO的队列去管理。 注意这里涉及到两种队列,一种的同步队列,当线程请求锁而等待的后将加入同步队列等待,而另一种则是等待队列(可有多个),通过Condition调用await ()方法释放锁后,将加入等待队列。
那么问题来了:明明是一个先进先出的队列,为什么还有公平锁非公平锁的概念。
答案: final Thread current = Thread.currentThread();
你可以在公平锁源码看到,他在任务获取锁的时候多了一个队列里面是否有值的判断,
当前线程未必是队列里面取到的,所以判断如果队列里面有值,先执 行队列里面的任务。
当然,AQS的队列带有头结点跟尾节点,尤其是头结点,作用巨大。
此节重点在于:带头尾节点的队列,怎么入队列出队列,公平锁非公平锁的实现方式。
附上两张照片:
JAVA并发框架是如何使用AQS的: ReentrantLock类使用同步状态来代表持有锁的数量,当一个锁被获得,会记录获取该锁的线程身份,如果一个非当前线程试图释放锁是不合法的。该类也使 用了ConditionObject类,和一些监视和检查方法。该类支持公平与非公平两种模式,是通过AQS的两个子类来实现的。 ReentrantReadWriteLock类将32位的state分成高位和低位,16位用于写锁计数,其余16位用于读锁计数。 Semaphore类使用同步状态保持当前计数,acquireShared减少计数,tryRelease的增加计数,如果state是正数就唤醒线程。 CountDownLatch类使用同步状态代表计数。所有线程都获得锁时,状态为0,就唤醒。
参考博客:
https://blog.csdn.net/javazejian/article/details/75043422
https://blog.csdn.net/liu88010988/article/details/50799793
如果有错误或者更好的说明,请在下发留言,我会在第一时间回复改正,谢谢!
我不能保证我会在程序员这一行业中一直走下去,但至少此刻,我的信念仍坚定不移。