Java Thread

线程状态及状态转换图

线程状态含义诱发动作
NEW新建线程对象,但尚未启动(start())。new Thread()
RUNNABLE一个可运行的线程,包含就绪(等待系统调度分配cpu时间片)和运行中(获得cpu时间片开始运行)两种状态。Ready: Thread.yield(),
Running: 被线程调度器选择
BLOCKED被阻塞等待监视器锁。IO阻塞,
等待进入同步代码块或方法
WAITING无限期等待另一个线程执行一个特定操作(通知或中断)。Object.wait(),
Thread.join(),
LockSupport.park()
TIMED_WAITING具有指定等待时间,可以在指定的时间内自行返回。Thread.sleep(long),
Object.wait(long timeout),
Thread.join(long timeout),
LockSupport.parkNanos(Object blocker, long nanos),
LockSupport.parkUntil(Object blocker, long deadline)
TERMINATED线程已经执行完毕。run()退出,
Thread.stop(),
线程中断退出,
阻塞IO被关闭

状态图

规整的状态图

显示锁和隐式锁的区别

synchronizedLock
关键字,隐式获取/释放锁接口,显式获取/释放锁
代码简单,被大多程序员广泛使用,默认推荐代码稍复杂,在try块外获取锁,在finally块中释放锁,迫于性能调优时再用
-可尝试非阻塞获取锁(线程尝试获取锁,若锁未被其他线程持有,则成功获取并持有锁)
-可中断获取锁(获取到锁的线程能够响应中断,当该线程被中断时,中断异常将被抛出,同时锁释放)
-可超时获取锁(在指定的截止时间之前获取锁,若超时仍无法获取锁,则返回)

锁是面向使用者的,它定义了使用者与锁交互的接口(比如可以允许两个线程并行访问),隐藏了实现细节; 同步器面向锁的实现者,它简化了锁的实现方式,屏蔽了同步状态管理、线程的排队、等待与唤醒等底层操作。

这里写图片描述

同步器可重写的方法

方法描述
boolean tryAcquire(int arg)独占式获取同步状态。实现该方法需要查询当前同步状态并判断是否符合预期,然后再进行CAS设置同步状态。
boolean tryRelease(int arg)独占式释放同步状态。等待获取同步状态的线程将有机会获取同步状态。
int tryAcquireShared(int arg)共享式获取同步状态。返回大于等于0的值表示获取成功,否则获取失败。
boolean tryReleaseShared(int arg)共享式释放同步状态。
boolean isHeldExclusively()同步状态是否在独占模式下被线程占用。

同步器提供的便捷方法

方法描述
void acquire(int arg)独占式获取同步状态,如果当前线程获取同步状态成功,则由该方法返回。否则,将会进入同步队列等待,该方法忽略中断
void acquireInterruptibly(int arg) throws InterruptedException同上,但该方法响应中断,在同步队列中等待的线程可以被中断,会抛出InterruptedException并返回。
boolean tryAcquireNanos(int arg, long nanosTimeout) throws InterruptedException同上且增加了超时限制,如果在超时时间内没有获取到同步状态将返回false,否则返回true。
boolean release(int arg)独占式释放同步状态。释放后会唤醒同步队列中的第一个节点所包含的线程。
void acquireShared(int arg)共享式获取同步状态,若同步未获取获取成功则会进入同步队列等待。与独占式获取主要区别在同一时刻可以有多个线程获取同步状态。
void acquireSharedInterruptibly(int arg) throws InterruptedException同上,但该方法响应中断
boolean tryAcquireSharedNanos(int arg, long nanosTimeout) throws InterruptedException同上且增加了超时限制
boolean releaseShared(int arg)共享式释放同步状态。

同步器中节点的含义

AQS#Node的属性含义
int waitStatus状态字段,仅可能取以下几种值:状态字段,仅可能取以下几种值:

SIGNAL: 当前节点的后继节点是(或不久的将来)阻塞的(通过park),因此当前节点释放或取消同步状态时必须通知(通过unpark)后继节点,为了避免竞争激烈,acquire方法必须首先表明他们需要一个启动信号,然后原子性重试获取同步状态,最后在失败时阻塞。
CANCELLED: 由于取消或中断,节点取消获取同步状态,节点进入该状态后将不会再发生变化。注意取消节点的线程永远不会再阻塞。
CONDITION: 此节点当前处于条件队列中。直到被转移(signal/signalAll)才会被加入到同步队列中,转移后状态将被设置为0。
PROPAGATE: releaseShared应该传播给其他节点。在doReleaseShared中设置(仅限头节点)以确保继续传播,即使其他操作已经介入。
0: 初始化状态
Node prev前驱节点,当节点加入到同步队列时被设置(CAS尾部加入)
Node next后继节点
Thread thread获取同步状态的线程
Node nextWaiter条件队列中的后继节点,或特殊值SHARED。因为条件队列只有在保持独占模式时才被访问,所以我们只需要一个简单的链接队列来在节点等待条件时保存节点。然后将它们转移到同步队列中以重新获取同步状态。并且因为condition只能是独占的,所以我们通过使用SHARED特殊值来指示共享模式。

同步队列和等待队列图示

同步队列和等待队列

AQS超时获取锁的源代码

    // acquire,acquireInterruptibly与此大同小异
    public final boolean tryAcquireNanos(int arg, long nanosTimeout)
            throws InterruptedException {
        if (Thread.interrupted()) 
            throw new InterruptedException();
        return tryAcquire(arg) || // 先尝试获取一次
            doAcquireNanos(arg, nanosTimeout); // 尝试失败,将其包装成Node,放入等待队列,并等待前驱节点唤醒
    }

    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; // 释放前驱节点引用,便于GC回收原头节点
                    failed = false;
                    return true;
                }
                nanosTimeout = deadline - System.nanoTime();
                if (nanosTimeout <= 0L) // 超时仍未获取到,则返回fasle
                    return false;
                if (shouldParkAfterFailedAcquire(p, node) && // 如果前驱节点状态(SIGNAL)正常,则等待;若已取消(CANCELLED)为其寻找一个正常的前驱节点;否则CAS设置前驱节点状态为正常态
                    nanosTimeout > spinForTimeoutThreshold) // 超时时间大于阈值,则使用parkNanos超时等待;否则采用高速自旋重试
                    LockSupport.parkNanos(this, nanosTimeout);
                if (Thread.interrupted()) // 被唤醒发现线程中断,则抛出中断异常
                    throw new InterruptedException();
            }
        } finally {
            if (failed) 
                cancelAcquire(node); // 超时或中断退出时,则取消获取同步状态
        }
    }

AQS释放锁的源代码

    public final boolean release(int arg) {
        if (tryRelease(arg)) { // 尝试释放同步状态
            Node h = head;
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h); // 释放成功,唤醒头节点的后继节点
            return true;
        }
        return false;
    }

    private void unparkSuccessor(Node node) {
        int ws = node.waitStatus;
        if (ws < 0) 
            compareAndSetWaitStatus(node, ws, 0); // 将头节点状态修改为0

        Node s = node.next;
        if (s == null || s.waitStatus > 0) { // 头节点不存在后继节点或后继节点已取消获取同步状态
            s = null; 
            // 从前往后寻找不一定能找到刚刚加入队列的后继节点, 因为在Node addWaiter(Node mode)中,是先CAS设置尾节点,再设置前驱节点和尾节点的引用关系
            for (Node t = tail; t != null && t != node; t = t.prev) 
                if (t.waitStatus <= 0) // 从队尾往前找,找到第一个需要唤醒的节点
                    s = t;
        }
        if (s != null)
            LockSupport.unpark(s.thread); // 唤醒线程
    }

AQS超时获取锁的流程图

doAcquireNanos

ReentrantLock非公平获取锁源代码

    // NonfairSync类中
    final void lock() {
        if (compareAndSetState(0, 1)) // 非公平锁直接尝试获取锁
            setExclusiveOwnerThread(Thread.currentThread());
        else
            acquire(1);
    }

    // Sync父类中
    final boolean nonfairTryAcquire(int acquires) {
        final Thread current = Thread.currentThread();
        int c = getState();
        if (c == 0) { // 目前没有其他线程获得锁,当前线程就可以尝试获取锁
            if (compareAndSetState(0, acquires)) { // CAS修改同步状态
                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; // 修改失败返回false
    }

ReentrantLock公平获取锁源代码

    // FairSync类中
    final void lock() {
        acquire(1);
    }

    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;
    }

ReentrantLock释放锁的源代码

    protected final boolean tryRelease(int releases) {
        int c = getState() - releases;
        if (Thread.currentThread() != getExclusiveOwnerThread()) // 当前线程未持有锁,不可释放
            throw new IllegalMonitorStateException();
        boolean free = false;
        if (c == 0) { // 由于锁可重入,当同步状态等于0时,才代表真正释放掉
            free = true;
            setExclusiveOwnerThread(null);
        }
        setState(c);
        return free;
    }

ReentrantReadWriteLock获取释放锁源代码

    /*以高16位表示所有线程获取读锁数,以低16位表示单个线程获取写锁数 */

    static final int SHARED_SHIFT   = 16;
    static final int SHARED_UNIT    = (1 << SHARED_SHIFT); // 0x00010000
    static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1; // 低16位全为1

    static int sharedCount(int c)    { return c >>> SHARED_SHIFT; } // 根据同步状态计算已持有的读锁数
    static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; } // 根据同步状态计算已持有的写锁数

    protected final boolean tryAcquire(int acquires) { // 获取独占锁(写锁)
        Thread current = Thread.currentThread();
        int c = getState();
        int w = exclusiveCount(c); // 持有的写锁数
        if (c != 0) { 
            // (Note: if c != 0 and w == 0 then shared count != 0)
            // 如果同步状态不为0但是写锁数为0,代表持有读锁(不为0)
            if (w == 0 || current != getExclusiveOwnerThread()) // 已持有读锁或不是当前线程持有写锁,均不可再获取写锁
                return false;
            if (w + exclusiveCount(acquires) > MAX_COUNT) // 获取写锁数超限
                throw new Error("Maximum lock count exceeded");
            setState(c + acquires); // 是当前线程持有写锁,可重入获取
            return true;
        }
        if (writerShouldBlock() || // 公平模式下需要判断同步队列中是否有前驱节点在等待
            !compareAndSetState(c, c + acquires)) // 无线程获取写锁,CAS获取锁
            return false;
        setExclusiveOwnerThread(current); // 获取成功
        return true;
    }

    protected final boolean tryRelease(int releases) {
        if (!isHeldExclusively()) // 非持有写锁的线程不可释放写锁
            throw new IllegalMonitorStateException();
        int nextc = getState() - releases;
        boolean free = exclusiveCount(nextc) == 0; // 因为可重入,当同步状态低16位全为0,才代表成功释放
        if (free)
            setExclusiveOwnerThread(null);
        setState(nextc); 
        return free;
    }

    protected final int tryAcquireShared(int unused) { // 获取共享锁(读锁)
        Thread current = Thread.currentThread();
        int c = getState();
        if (exclusiveCount(c) != 0 &&
            getExclusiveOwnerThread() != current) // 写锁已被持有但不是当前线程,获取读锁阻塞
            return -1;
        int r = sharedCount(c); // 持有的读锁数
        if (!readerShouldBlock() && // 公平模式下需要判断同步队列中是否有前驱节点在等待
            r < MAX_COUNT &&
            compareAndSetState(c, c + SHARED_UNIT)) { // 无线程持有写锁,所有线程都可获取读锁
            if (r == 0) { // 无线程持有读锁,标记当前线程首次获取读锁1次
                firstReader = current;
                firstReaderHoldCount = 1;
            } else if (firstReader == current) { // 有线程持有读锁,若当前线程是首次获取读锁的线程,则增加读锁持有数
                firstReaderHoldCount++;
            } else { // 有线程持有读锁,但不是首次获取读锁的线程,则初始化线程相应读锁持有数
                HoldCounter rh = cachedHoldCounter;
                if (rh == null || rh.tid != getThreadId(current)) // 无缓存或缓存的计数不是当前线程
                    cachedHoldCounter = rh = readHolds.get(); // 获取线程本地缓存
                else if (rh.count == 0)  // 有缓存且当前线程第一次获取锁,则初始化线程(锁计数)本地缓存
                    readHolds.set(rh);
                rh.count++; // 当前线程持有读锁数加1
            }
            return 1;
        }
        return fullTryAcquireShared(current); // 自旋获取读锁,用于应对首次尝试CAS未命中和重入读锁的情况
    }

    protected final boolean tryReleaseShared(int unused) {
        Thread current = Thread.currentThread();
        if (firstReader == current) { // 当前线程是第一个获取读锁的线程
            // assert firstReaderHoldCount > 0;
            if (firstReaderHoldCount == 1) // 线程仅持有1个读锁,释放后即无第一个读线程
                firstReader = null;
            else
                firstReaderHoldCount--; 
        } else {
            HoldCounter rh = cachedHoldCounter;
            if (rh == null || rh.tid != getThreadId(current))
                rh = readHolds.get();
            int count = rh.count;
            if (count <= 1) { // 只获取一次读锁,则直接移除,
                readHolds.remove();
                if (count <= 0)
                    throw unmatchedUnlockException();
            }
            --rh.count; // 减少缓存计数信息
        }
        for (;;) { // 自旋释放读锁
            int c = getState();
            int nextc = c - SHARED_UNIT;
            if (compareAndSetState(c, nextc))
                // Releasing the read lock has no effect on readers,
                // but it may allow waiting writers to proceed if
                // both read and write locks are now free.
                return nextc == 0;
        }
    }

参考: 《Java并发编程的艺术》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值