jdk Collection和concurrent包 --第二篇

queue队列(接上一章):

https://www.cnblogs.com/lemon-flm/p/7877898.html

先看 java.util.concurrent 包 里 除去atomic和locks 两个package,有哪些重要的类(有点多,一个截图 放不下)

 

首先看接口 BlockingQueue 以及其实现类:

找到一个不错的博客,很全:

http://www.cnblogs.com/skywang12345/p/3496098.html

Java多线程系列--“JUC锁”02之 互斥锁ReentrantLock

其中condition的 await 和 signal 相当于 thread 的wait 和 notify 。

condition 的 await 和 signal 需要配套使用,signal 唤醒的是 相同condition 的await线程。

await 和wait 一样,会释放锁。

 

1. AQS -- 指AbstractQueuedSynchronizer类。
    AQS是java中管理“锁”的抽象类,锁的许多公共方法都是在这个类中实现。AQS是独占锁(例如,ReentrantLock)和共享锁(例如,Semaphore)的公共父类。

2. AQS锁的类别 -- 分为“独占锁”和“共享锁”两种。
    (01) 独占锁 -- 锁在一个时间点只能被一个线程锁占有。根据锁的获取机制,它又划分为“公平锁”和“非公平锁”。公平锁,是按照通过CLH等待线程按照先来先得的规则,公平的获取锁;而非公平锁,则当线程要获取锁时,它会无视CLH等待队列而直接获取锁。独占锁的典型实例子是ReentrantLock,此外,ReentrantReadWriteLock.WriteLock也是独占锁。
    (02) 共享锁 -- 能被多个线程同时拥有,能被共享的锁。JUC包中的ReentrantReadWriteLock.ReadLock,CyclicBarrier, CountDownLatch和Semaphore都是共享锁。这些锁的用途和原理,在以后的章节再详细介绍。

3. CLH队列 -- Craig, Landin, and Hagersten lock queue
    CLH队列是AQS中“等待锁”的线程队列。在多线程中,为了保护竞争资源不被多个线程同时操作而起来错误,我们常常需要通过锁来保护这些资源。在独占锁中,竞争资源在一个时间点只能被一个线程锁访问;而其它线程则需要等待。CLH就是管理这些“等待锁”的线程的队列。
    CLH是一个非阻塞的 FIFO 队列。也就是说往里面插入或移除一个节点的时候,在并发条件下不会阻塞,而是通过自旋锁和 CAS 保证节点插入和移除的原子性。

4. CAS函数 -- Compare And Swap 
    CAS函数,是比较并交换函数,它是原子操作函数;即,通过CAS操作的数据都是以原子方式进行的。例如,compareAndSetHead(), compareAndSetTail(), compareAndSetNext()等函数。它们共同的特点是,这些函数所执行的动作是以原子的方式进行的。

 

 

// waitStatus为“CANCELLED, SIGNAL, CONDITION, PROPAGATE”时分别表示不同状态,
(03) Node通过waitStatus保存线程的等待状态。
(04) Node通过nextWaiter来区分线程是“独占锁”线程还是“共享锁”线程。如果是“独占锁”线程,则nextWaiter的值为EXCLUSIVE;如果是“共享锁”线程,则nextWaiter的值是SHARED。


说明:
(01) 关于waitStatus请参考下表(中扩号内为waitStatus的值),更多关于waitStatus的内容,可以参考前面的Node类的介绍。

CANCELLED[1]  -- 当前线程已被取消
SIGNAL[-1]    -- “当前线程的后继线程需要被unpark(唤醒)”。一般发生情况是:当前线程的后继线程处于阻塞状态,而当前线程被release或cancel掉,因此需要唤醒当前线程的后继线程。
CONDITION[-2] -- 当前线程(处在Condition休眠状态)在等待Condition唤醒
PROPAGATE[-3] -- (共享锁)其它线程获取到“共享锁”
[0]           -- 当前线程不属于上面的任何一种状态。
 

 

公平锁的获取流程:

(01) 先是通过tryAcquire()尝试获取锁。获取成功的话,直接返回;尝试失败的话,再通过acquireQueued()获取锁。
(02) 尝试失败的情况下,会先通过addWaiter()来将“当前线程”加入到"CLH队列"末尾;然后调用acquireQueued(),在CLH队列中排序等待获取锁,在此过程中,线程处于休眠状态。
直到获取锁了才返回。 如果在休眠等待过程中被中断过,则调用selfInterrupt()来自己产生一个中断。

公平锁和不公平锁的区别:

公平锁和非公平锁的区别,是在获取锁的机制上的区别。表现在,在尝试获取锁时 —— 公平锁,只有在当前线程是CLH等待队列的表头时,才获取锁;而非公平锁,只要当前锁处于空闲状态,则直接获取锁,而不管CLH等待队列中的顺序。
只有当非公平锁尝试获取锁失败的时候,它才会像公平锁一样,进入CLH等待队列排序等待。

代码上区别是  tryAcquire 方法里 有没有 hasQueuedPredecessors()判断(即当前线程在clh队列中, 前面有无等待的线程)。

  公平锁:
  protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
            //当前线程在clh队列中, 前面有无等待的线程
                if (!hasQueuedPredecessors() &&
                    compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0)
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }

 

        非公平锁:
         final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }

 

 

接 下一章


每个线程安全类的底层实现 做分类
https://blog.csdn.net/lh87522/article/details/45973373
https://blog.csdn.net/windsunmoon/article/details/36903901


java.util.concurrent.atomic
每个线程安全类的底层实现 使用CAS吗?

java.util.concurrent.locks?
看可重入锁, 读写锁

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
JDK是"Java Development Kit"(Java开发工具)的缩写,它是一个开发Java程序的软件JDK含了Java编程语言的编译器(javac),Java运行时环境(JRE),以及其他开发工具和库。通过JDK,开发者可以编写、编译和运行Java程序。 而ld-linux-x86-64.so.2是一个动态链接器,它是Linux操作系统上用于加载和链接共享库的重要组件。在Linux系统上,通常会使用动态链接库来共享公共的代码和函数,以降低程序的内存占用和提高效率。ld-linux-x86-64.so.2会在程序运行时自动加载和链接所需的共享库,以便程序能够正常执行。 JDK和ld-linux-x86-64.so.2在不同的领域扮演着不同的角色。JDK是开发Java程序的工具,它提供了编译、运行和调试Java代码的环境。开发者可以使用JDK编写和测试Java程序,并且进行性能优化和错误调试。 而ld-linux-x86-64.so.2是操作系统级别的组件,它在程序执行过程中负责加载和链接共享库,以便程序能够正常运行。在Linux系统中,很多应用程序都依赖于各种共享库,而ld-linux-x86-64.so.2会在程序启动时自动加载这些共享库,并将它们链接到程序中。 总结来说,JDK是用于开发Java程序的工具,而ld-linux-x86-64.so.2是Linux操作系统上的动态链接器,用于加载和链接共享库。它们在不同的层级上发挥着不同的作用,但都对程序的编译、运行和执行起着重要的作用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值