1

Java全家桶

集合

List

ArrayList
LinkedList

Set

Map

异常

异常的分类

Throwable、Exception、Error。Exception是可以被程序处理的异常,Error是不能被处理的错误,Exception又分别编译时Exception和运行时Exception,其中编译时Exception在代码调用处必须显示处理或抛出。

处理异常的最佳实现

  1. 涉及到外部资源的,要配合finally来释放资源;
  2. 在方法签名中声明异常要详细,不要直接抛出Exception或Throwable;
  3. 要再javadoc中提现异常信息;
  4. 正确描述异常信息,能够帮助快速定位问题,描述方式可以用特定类型的异常,也可以通过message来描述;
  5. 在编写处理异常的代码块时,要优先处理范围更小的特定异常;
  6. 不用吞掉异常,要记录、处理或抛出异常;
  7. 不要同时记录 并且 抛出异常,这会造成多个异常现场,不利益排查问题;
  8. 对于特定的模块、框架或工具,可以将异常统一包装成某个特定类型,方便统一处理和缩小排查问题的范围;

并发中的异常处理

异常的范围是线程,如果在一个线程中抛出了异常,这个线程就会中断。

  1. 利用try...catch进行处理;
  2. 设置线程级别的异常处理器;

    class MyUncheckedExceptionHandler implements Thread.UncaughtExceptionHandler {
             @Override
             public void uncaughtException(Thread t, Throwable e) {
                 System.out.println("捕获到异常。异常栈信息为:");
                 e.printStackTrace();
         }
         thread.setUncaughtExceptionHandler(new MyUncheckedExceptionHandler());
  3. 设置全局异常处理器;

    Thread.setDefaultUncaughtExceptionHandler(new MyUncheckedExceptionHandler());
  4. 通过FutureTask将线程内异常传递到调用线程;

    FutureTask<Integer> futureTask = new FutureTask<>(new Callable<Integer>() {
             @Override
             public Integer call() throws Exception {
                 System.out.println("子线程运行开始");
                 return 1 / 0;
             }
         });
  5. 对于一些比如基于spring mvc的web项目,一般会通过ExceptionHandler来处理异常;

IO

并发

当考虑在程序中引入多线程时,大部分情况是想解决程序的性能问题,另外也有可能是为了更好的编程模型,但引入一个新事物就会带来新的问题,并发编程也是如此。

  1. 多线程上下文切换会带来性能损耗
    在线程数>cpu核数的情况下程序的并发执行是通过cpu切换时间片实现的,cpu在多个线程之间切换时间片时需要记录当前线程的状态,这就会带来时间和空间上的开销,所以,如果引入多线程带来的性能提升被线程上下文切换地消失,就需要重新考虑是否需要多线程。
  2. 死锁问题
    死锁会让线程一直处于wait状态,这会体现在业务上,所以死锁一般是不可接受的。出现死锁的原因在于多个线程之间互相等待对方是否资源,有以下几种方法可以在一定程度上避免出现死锁
    a. 避免在处理逻辑中获取多个锁资源或嵌套锁
    b. 使用超时锁来避免线程在死锁状态下一直wait
  3. 资源限制
    程序性能提升的上限是所依赖的外部资源,而外部资源主要分为两种:硬件资源软件资源,硬件资源例如cpu、磁盘读写速度、网卡带宽等,软件资源比如数据库连接和socket连接等,在资源限制范围之外使用多线程不仅不会带来性能提升,反而会让程序变得更慢。如果存在硬件资源限制,就要将并发数降低到资源可承受范围内,如果是软件资源限制,就要尽量将资源池化实现复用或尽量少的获取。

Java内存模型

并发编程的挑战主要来自两个方面,一是设计编程模型,二是解决并发安全问题,其中编程模型的设计属于程序员的工作,而解决并发安全问题是java的工作,换句话说,java要给程序员提供解决并发安全问题的工具。

在了解java内存模型之前先了解以下操作系统的内存模型,这有利于理解产生并发安全问题的根本原因。

image.png

现代计算机的cpu为了避免主内存的读写速度影响计算速度,都会引入多级高速缓存,在计算时先将数据从主内存加载到高速缓存中,计算完成后再写入主内存中,但在多cpu的硬件架构下会出现数据不一致的问题,为此引入了一种叫做MESI的缓存一致性协议,MESI的全称是Modified-Exclusive-Shared-Invalid,具体的含义如下:

假如有两个线程,要对主内存中的变量x执行x+=1操作;
1. 将线程A从主内存中将x变量读取到高速缓存时,总线上变量x的状态为E;
2. 线程B从主内存中将x变量读取到高速缓存总,总线上变量x的状态为S;
3. 线程A将计算结果写入主内存中,总线上变量x的状态为S;
4. 线程A写入x完成后,总线上变量x的状态为I,此时线程B再读取x时,会发现x已失效,
   然后会重新从主内存中读取x到高速缓存;

除此之外,现代cpu还会使用一种叫做指令重排序的技术来提高性能,即保证最终结果正确的情况下,改变cpu指令的执行顺序。java编译器的指令重排序实际也是这个道理。

以此为基础,我们所说的JMM(java内存模型)就可以从两个方面来理解:

  1. java线程模型
  2. 线程安全性保证

image.png

在java中,每个线程都有自己的工作内存,也就是线程栈,整体的结构类似于cpu/多级缓存,然后通过JMM来解决数据的线程安全问题。

而这里的JMM简单理解就是java提供的各种同步工具,比如synchronized/volatile/final/ReentrantLock/CountdownLatch等。

线程基础

线程与进程

进程是操作系统分配资源的基本单位,线程是cpu运行的基本单位,一个进程内包含多个线程。

并发与并行

并发指的是两个或多个线程间隔发生;
并行指的是两个或多个线程在同一时刻同时发生;
并发得益于cpu时间片轮转,并行得益于多cpu和多核cpu的硬件架构;

创建线程的方式

new Thread().start();
new Runnable();
new Callable();
new FutureTask(Runnale/Callable)

守护线程

守护线程是一种支持线程,当主线程停止后,守护线程会立马终止。

package concurrent;

import java.util.concurrent.TimeUnit;

public class Daemon {
    public static void main(String[] args) {
        Thread t = new Thread(new DaemonRunner());
        t.setDaemon(true);
        t.start();
    }
}

 class DaemonRunner implements Runnable {
    @Override
    public void run() {
        try  {
            TimeUnit.SECONDS.sleep(10);
        }catch (Exception ex) {}finally {
            //无效,主线程退出后,守护线程会立马终止
            System.out.println("Daemon finally");
        }
    }
}
线程中断

中断是一种线程是否被中断了的标识,通过Thread.interrupt()方法对某个线程进行中断,此时该线程的中断标识=true(Thread.isInterrupted()),但如果是调用Thread.interrupted(),它会返回中断状态的同时,复位中断状态,另外当线程抛出InterruptedException时,中断状态也会被复位。

wait/notify
public class WaitNotify {
    static boolean flag = true;
    static Object lock = new Object();
    static class Wait implements Runnable {
        @Override
        public void run() {
            synchronized (lock) {
                while (flag) {
                    try {
                        System.out.println(Thread.currentThread() + " flag is true. wait@" +
                                new SimpleDateFormat("HH:mm:ss").format(new Date()));
                        lock.wait();
                    }catch (Exception ex) {}
                }
                System.out.println(Thread.currentThread() + " flag is false. running @" +
                        new SimpleDateFormat("HH:mm:ss").format(new Date()));
            }
        }
    }

    static class Notify implements Runnable {
        @Override
        public void run() {
            synchronized (lock) {
                System.out.println(Thread.currentThread() + " hold lock. notify@" +
                        new SimpleDateFormat("HH:mm:ss").format(new Date()));

                lock.notifyAll();
                flag = false;
                try {
                    TimeUnit.SECONDS.sleep(5);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            synchronized (lock) {
                System.out.println(Thread.currentThread() + "hold lock again. sleep@"
                        + new SimpleDateFormat("HH:mm:ss").format(new Date()));
                try {
                    TimeUnit.SECONDS.sleep(5);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
join

如果主线程通过join的方式将另一个线程A加入到执行序列中,那么主线程会一致等待线程A执行完成,才能继续往下执行。

public static void main(String[] args) throws Exception {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    TimeUnit.SECONDS.sleep(5);
                    System.out.println("join thread");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        thread.start();
        thread.join();
        System.out.println("main thread");
}

同步组件

synchronized

synchronized在java中是实现同步的最常用的工具,在java6之前它是一个重量级的锁,但在java6及以后引入了偏向锁和轻量级锁,性能得到了很大的提升。synchronized的用法主要有三种:

  1. 用在静态方法上,锁对象是当前类的class对象;
  2. 用在成员方法上,锁对象是当前对象;
  3. 同步代码块,锁对象是指定的对象;

synchronized在编译时java编译器会自动插入一组monitorenter和monitorexit指令,从而让cpu实现同步的功能。

下面说说synchronized的四种不同是锁状态:无锁、偏向锁、轻量级锁和重量级锁,当只有一个线程获取锁时,锁状态为偏向锁,此时并不会真正的加锁,而是设置锁对象的对象头的偏向线程id为当前线程,当有多个线程同时获取锁,但锁能够很快得到释放时,偏向锁会膨胀成轻量级锁,轻量级锁的原理相比于偏向锁要复杂一些,首先尝试获取锁的线程会将锁对象的对象头复制到线程栈中,然后用cas的方式将锁对象的对象头指向自己线程栈中的锁对象头,抢占成功的线程就成功的获取了锁,但如果锁竞争继续加剧,轻量级锁就会膨胀为重量级锁,也就是会造成线程wait。java6引入了偏向锁和轻量级锁后,synchronized的性能得到了很大的提升,因为很多时候,synchronized都是处于这两种状态。

cas

cas是compare and set的缩写,是一种无锁实现线程安全的修改的方式,一般会配合while循环一起使用。juc中提供了的一系列atomic工具,底层就是基于cas实现无锁更新的,能够替换传统的重量级同步,提升程序的性能你。

volatile

被volatile修饰的变量能保证内存可见性,一般像一些状态变量都会用volatile来修饰。在原理方面,java编译器进行编译的时候,会插入一个Lock#指令,这个指令会使得cpu缓存中当前变量的副本值失效,从而重新从主内存中读取数据,可以理解成是基于SEMI协议的一种一致性保证。

atomic

atomic包中的类基本都是利用cas+自旋的方式实现无锁的线程安全操作的,主要的atomic工具类有如下这些:

AtomicInteger
AtomicBoolean
AtomicLong
AtomicReference
AtomicStampedReference
AtomicIntegerArray
AtomicLongArray
AtomicReferenceArray
AtomicIntegerFieldUpdater
AtomicLongFieldUpdater
AtomicReferenceUpdater
Lock
Lock lock = new ReentrantLock();
lock.lock();
try {
    ....
}finally {
    lock.unlock();
}

相比于sychronized,Lock锁具有如下优势:

  1. 能够非阻塞的尝试获取锁
  2. 锁能够响应中断
  3. 获取锁时支持超时
AQS

AQS的全称是AbsractQueuedSynchronizer,它是juc包中一个非常重要的同步器,很多高级的同步组件都是基于AQS实现的。在AQS内部有一个int类型的状态变量,然后通过内部的同步/等待队列来实现现在的互斥等待。使用AQS时,一般是提供了一个AQS的子类,然后通过AQS提供的方法来操作内部的状态变量,进而修改同步状态。

getState()
setState(int newState)
compareAndSetState(int expect, int update);

举例如下:

public class Mutex implements Lock {
    //内置AQS同步组件
    private static class Sync extends AbstractQueuedSynchronizer {
        @Override
        protected boolean isHeldExclusively() {
            return getState() == 1;
        }
        @Override
        protected boolean tryAcquire(int acquires) {
            if (compareAndSetState(0, 1)) {
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }
        @Override
        protected boolean tryRelease(int arg) {
            if (getState() == 0) {
                throw new IllegalMonitorStateException();
            }
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }
        Condition newCondition() {
            return new ConditionObject();
        }
    }
    private final Sync sync = new Sync();
    @Override
    public void lock() {
        sync.acquire(1);
    }
    @Override
    public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }
    @Override
    public boolean tryLock() {
        return sync.tryAcquire(1);
    }
    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return sync.tryAcquireSharedNanos(1, unit.toNanos(time));
    }
    @Override
    public void unlock() {
        sync.release(1);
    }
    @Override
    public Condition newCondition() {
        return sync.newCondition();
    }
}

AQS通过同步队列和等待队列实现互斥和等待通知的,队列中的节点为Node,内部结构如下:

属性描述
waitStatusCANCELLED -> 超时或中断; SIGNAL -> 释放同步状态时通知后继节点; CONDITION -> 在等待队列中; PROPAGATE -> 共享模式下唤醒后继节点时,无条件向后传播;INITIAL -> 初始状态
prev前驱节点
next后继节点
nextWait等待队列中的后继节点
thread等待队列中的后继节点

同步队列:同步队列是一个FIFO队列,用来存放获取同步状态失败的线程,具体结构如下图所示。
image.png
当某个线程获取同步线程失败后,会被构造成一个Node节点然后通过cas加自旋的方式添加到同步队列的末尾;同步队列的头节点是成功获取同步状态的线程,当同步状态被释放后,会通过LockSupport.unpark唤醒它的后继节点代表的线程,从而实现了一个FIFO队列。

独占模式:借助AQS的acquire/relase方法就可以实现独占模式(例如ReentrantLock),下面看一下这两个方法的具体逻辑(总的流程和上述同步队列的处理流程一致)。

public final void acquire(int arg) {
        //尝试获取同步状态
        if (!tryAcquire(arg) &&
           //进入自旋状态
            acquireQueued(
                //构造Node节点并添加到同步队列末尾
               addWaiter(Node.EXCLUSIVE), arg)
               )
            selfInterrupt();
}


private Node addWaiter(Node mode) {
        Node node = new Node(Thread.currentThread(), mode);
        // Try the fast path of enq; backup to full enq on failure
        Node pred = tail;
        //快速尝试,如果失败再走cas + 自旋
        if (pred != null) {
            node.prev = pred;
            if (compareAndSetTail(pred, node)) {
                pred.next = node;
                return node;
            }
        }
        enq(node);
        return node;
}

private Node enq(final Node node) {
         //自旋 + cas 线程安全的将节点加入到同步队列末尾
        for (;;) {
            Node t = tail;
            if (t == null) { // Must initialize
                if (compareAndSetHead(new Node()))
                    tail = head;
            } else {
                node.prev = t;
                //cas
                if (compareAndSetTail(t, node)) {
                    t.next = node;
                    return t;
                }
            }
        }
}

final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
            boolean interrupted = false;
            //进入自旋 + 阻塞状态
            for (;;) {
                final Node p = node.predecessor();
                //如果前驱节点时头节点,并且获取同步状态成功,则成功获取同步状态
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return interrupted;
                }
                
                if (shouldParkAfterFailedAcquire(p, node) &&
                   //否则将当前线程通过LockSupport.park挂起
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
}

//释放同步状态
public final boolean release(int arg) {
        //通过模板方法释放同步状态
        if (tryRelease(arg)) {
            Node h = head;
            if (h != null && h.waitStatus != 0)
                 //唤醒后继节点
                unparkSuccessor(h);
            return true;
        }
        return false;
}

独占模式下获取同步状态的具体流程如下:
image.png

共享模式:共享模式在获取同步状态和释放同步状态时与独占模式都有所区别

  1. 获取同步状态时,只要tryAcquireShare返回值>0,就表示成功;
  2. 在释放同步状态时,由于可能存在多个线程同时释放的情况,所以需要通过cas+自旋的方式来线程安全的释放同步状态;

获取同步状态:

public final void acquireShared(int arg) {
        if (tryAcquireShared(arg) < 0)
            doAcquireShared(arg);
}
public final void acquireShared(int arg) {
        if (tryAcquireShared(arg) < 0)
            doAcquireShared(arg);
}

private void doAcquireShared(int arg) {
        //添加节点到队列尾部
        final Node node = addWaiter(Node.SHARED);
        boolean failed = true;
        try {
            boolean interrupted = false;
            //进入到自旋转状态
            for (;;) {
                final Node p = node.predecessor();
                //判断前驱节点是否为头节点
                if (p == head) {
                    int r = tryAcquireShared(arg);
                    //尝试获取同步状态
                    if (r >= 0) {
                        setHeadAndPropagate(node, r);
                        p.next = null; // help GC
                        if (interrupted)
                            selfInterrupt();
                        failed = false;
                        return;
                    }
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
}

释放同步状态:

public final boolean releaseShared(int arg) {
        if (tryReleaseShared(arg)) {
            doReleaseShared();
            return true;
        }
        return false;
}

private void doReleaseShared() {
        //自旋+ CAS
        for (;;) {
            Node h = head;
            if (h != null && h != tail) {
                int ws = h.waitStatus;
                if (ws == Node.SIGNAL) {
                    if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
                        continue;            // loop to recheck cases
                    unparkSuccessor(h);
                }
                else if (ws == 0 &&
                         !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
                    continue;                // loop on failed CAS
            }
            if (h == head)                   // loop if head changed
                break;
        }
    }

响应中断:响应中断的逻辑其实就是在自旋的过程中,判断线程的中断状态,并抛出InterrutedException。有一点需要注意,如果当前线程已经在同步队列中等待,那么即使对线程执行中断也也不会立即抛出异常,而是等到线程被前驱节点唤醒后才能响应中断。

public final void acquireInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        if (!tryAcquire(arg))
            doAcquireInterruptibly(arg);
}

private void doAcquireInterruptibly(int arg)
        throws InterruptedException {
        final Node node = addWaiter(Node.EXCLUSIVE);
        boolean failed = true;
        try {
            for (;;) {
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return;
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    //从自旋等待中恢复后,如果被中断,则抛出异常
                    throw new InterruptedException();
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
}

超时获取同步状态:超时锁的核心逻辑是要保证超时时间的准确

public final boolean tryAcquireNanos(int arg, long nanosTimeout)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        return tryAcquire(arg) ||
            doAcquireNanos(arg, nanosTimeout);
}


private boolean doAcquireNanos(int arg, long nanosTimeout)
            throws InterruptedException {
        if (nanosTimeout <= 0L)
            return false;
        final long deadline = System.nanoTime() + nanosTimeout;
        final Node node = addWaiter(Node.EXCLUSIVE);
        boolean failed = true;
        try {
            for (;;) {
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return true;
                }
                //计算剩余时间
                nanosTimeout = deadline - System.nanoTime();
                //如果小于0则超时
                if (nanosTimeout <= 0L)
                    return false;
                if (shouldParkAfterFailedAcquire(p, node) &&
                    //如果>1000ms,则将当前线程挂起,否则不挂起,进入自旋等待,保证时间的准确性
                    nanosTimeout > spinForTimeoutThreshold)
                    LockSupport.parkNanos(this, nanosTimeout);
                if (Thread.interrupted())
                    throw new InterruptedException();
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
}
ReentrantLock

ReentrantLock是基于AQS的独占模式构造的一个同步锁,具体的实现原理如下:

//在ReentrantLock锁的内部,构造了一个AQS的子类,然后复写相关方法
//操作同步状态
//ReentrantLock支持公平模式和非公平模式,非公平模式在获取锁是能够
//对同步状态进行抢占,而公平模式则是乖乖的进行排队
abstract static class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = -5179523762034025860L;

        /**
         * Performs {@link Lock#lock}. The main reason for subclassing
         * is to allow fast path for nonfair version.
         */
        abstract void lock();

        /**
         * Performs non-fair tryLock.  tryAcquire is implemented in
         * subclasses, but both need nonfair try for trylock method.
         */
        final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            //公平模式获取同步状态,立即进行抢占,如果抢占成功则返回true
            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;
        }

        protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }

        //持有锁的线程的判断
        protected final boolean isHeldExclusively() {
            // While we must in general read state before owner,
            // we don't need to do so to check if current thread is owner
            return getExclusiveOwnerThread() == Thread.currentThread();
        }

        //返回一个等待队列,用来实现等待通知机制
        final ConditionObject newCondition() {
            return new ConditionObject();
        }

        // Methods relayed from outer class

        final Thread getOwner() {
            return getState() == 0 ? null : getExclusiveOwnerThread();
        }

        final int getHoldCount() {
            return isHeldExclusively() ? getState() : 0;
        }

        final boolean isLocked() {
            return getState() != 0;
        }

        /**
         * Reconstitutes the instance from a stream (that is, deserializes it).
         */
        private void readObject(java.io.ObjectInputStream s)
            throws java.io.IOException, ClassNotFoundException {
            s.defaultReadObject();
            setState(0); // reset to unlocked state
        }
    }

    /**
     * Sync object for non-fair locks
     * 非公平模式
     */
    static final class NonfairSync extends Sync {
        private static final long serialVersionUID = 7316153563782823691L;

        /**
         * Performs lock.  Try immediate barge, backing up to normal
         * acquire on failure.
         */
        final void lock() {
            //立即抢占
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }

        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
    }

    /**
     * Sync object for fair locks
     */
    static final class FairSync extends Sync {
        private static final long serialVersionUID = -3000897897090466540L;

        //公平模式,直接进行排队
        final void lock() {
            //前面讲到,AQS内部会调用tryAcquire
            acquire(1);
        }

        /**
         * Fair version of tryAcquire.  Don't grant access unless
         * recursive call or no waiters or is first.
         */
        protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                //如果没有等待线程,并且获取同步状态成功了,表示获取锁成功
                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;
        }
    }
ReentrantReadWriteLock
CountdownLatch
CyclicBarrier
Semaphore
Exchanger
Phaser
并发容器
ConcurrentHashMap
CopyOnWriteArrayList
ConcurrentLinkedQueue
阻塞队列
ArrayBlockingQueue:由数组组成的有界阻塞队列
LinkedBlockingQueue:由链表组成的有界阻塞队列
PriorityBlockingQueue:支持优先级排序的无界阻塞队列
DelayQueue:使用优先级队列实现的无界阻塞队列
SynchronousQueue:不存储元素的阻塞队列
LinkedTransferQueue:由链表组成的无界阻塞队列
LinkedBlockingDeque:由链表组成的双向阻塞队列
Fork/Join

JVM


echo
23 声望0 粉丝

生命中最难的阶段,不是没人懂你,而是你不懂自己。