JAVA 多线程面试题

导读:本篇文章讲解 JAVA 多线程面试题,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

线程的状态

参考Java线程的6种状态及切换(透彻讲解)
在这里插入图片描述

线程池

线程池参数 老八股文了。俩个时间参数是 线程空闲回收时间,回收时候用的。
execute 提交时候的流程 老八股文了。
线程回收条件

while (task != null || (task = getTask()) != null) {
//task  为null 会去 拿线程执行,拿不到就回收。
}
拿不到的条件。
1、队列空。线程池停了等情况
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
                decrementWorkerCount();
                return null;
            }
2、 (工作线程大于最小线程 || 超过空闲时间)&&(工作线程大于1 || 队列空)
工作线程大于1 是应为自己停了怎么也得有个在运行的,队列空就不需要了
 int wc = workerCountOf(c);
// Are workers subject to culling?
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
if ((wc > maximumPoolSize || (timed && timedOut))
                && (wc > 1 || workQueue.isEmpty())) {
                if (compareAndDecrementWorkerCount(c))
                    return null;
                continue;
            }

笔试题

ab俩个线程交替打印,

可以取个巧直接用synchronized wait notifyAll

Object o = new Object();
        AtomicInteger count = new AtomicInteger(0);
        new Thread(new P("a", o, count),"aaa").start();
        new Thread(new P("b", o, count),"bbb").start();

static class P implements Runnable{
        String info;
        final Object lock;
        AtomicInteger count;

        public P(String info, Object lock, AtomicInteger count) {
        //省略
        }

        @SneakyThrows
        @Override
        public void run() {
            synchronized (lock){
                while (this.count.get() < 20){
                   log.info(info + "" +count.incrementAndGet());
                    lock.notifyAll();
//                    lock.wait();
                    lock.wait(1000*20);
                    log.info("100毫秒");
                }    
            }
        }
    }

三个线程交替打印

用ReentrantLock的Condition

public static void main(String[] args){
        AtomicInteger count = new AtomicInteger(0);

        ReentrantLock lock = new ReentrantLock();
        // 声明互相等待的条件
        Condition condition1 = lock.newCondition();
        Condition condition2 = lock.newCondition();
        Condition condition3 = lock.newCondition();
        new Thread(new P2(lock,condition1,condition2,"a",  count),"aaa").start();
        new Thread(new P2(lock,condition2,condition3,"b",  count),"bbb").start();
        new Thread(new P2(lock,condition3,condition1,"c",  count),"ccc").start();
        lock.lock();
        condition1.signal();
        lock.unlock();
    }
    
static class P2 implements Runnable{
        public P2(ReentrantLock lock,Condition condition, Condition conditionNext, String info, AtomicInteger count) {
            this.lock = lock;
            this.condition = condition;
            this.conditionNext = conditionNext;
            this.info = info;
            this.count = count;
        }
        ReentrantLock lock;
        Condition condition;
        Condition conditionNext;
        String info;
        AtomicInteger count;
        @SneakyThrows
        @Override
        public void run() {
                while (this.count.get() < 20) {
                    lock.lock();
                    condition.await();
                    log.info(info + "" + count.incrementAndGet());
                    conditionNext.signal();
                    lock.unlock();
                }    
                
            }
            
        }

AQS (AbstractQueuedSynchronizer)

参考Java并发之AQS详解
抽象的队列式的同步器,AQS定义了一套多线程访问共享资源的同步器框架,子类只需维护volatile int status(共享资源数量) 就可以。至于具体线程等待队列的维护(如获取资源失败入队/唤醒出队等),AQS已经在顶层实现好了。
主要实现四个方法 都是返回boolean类型的。

  • isHeldExclusively():该线程是否正在独占资源。只有用到condition才需要去实现它。
  • tryAcquire(int):独占方式。尝试获取资源,成功则返回true,失败则返回false。
  • tryRelease(int):独占方式。尝试释放资源,成功则返回true,失败则返回false。
  • tryAcquireShared(int):共享方式。尝试获取资源。负数表示失败;0表示成功,但没有剩余可用资源;正数表示成功,且有剩余资源。
  • tryReleaseShared(int):共享方式。尝试释放资源,如果释放后允许唤醒后续等待结点返回true,否则返回false。

内部类Node

双向列表的Node。节点核心参数 waitStatus 、thread。
addWaiter的时候会创建Node。addWaiter就是追加一个Node到队列尾。
Node的 五种状态 (waitStatus的四个值)

  • CANCELLED(1):表示当前结点已取消调度。当timeout或被中断(响应中断的情况下),会触发变更为此状态,进入该状态后的结点将不会再变化
  • SIGNAL(-1):表示后继结点在等待当前结点唤醒。后继结点入队时,会将前继结点的状态更新为SIGNAL
  • CONDITION(-2):表示结点等待在Condition上,当其他线程调用了Condition的signal()方法后,CONDITION状态的结点将从等待队列转移到同步队列中,等待获取同步锁
  • PROPAGATE(-3):共享模式下,前继结点不仅会唤醒其后继结点,同时也可能会唤醒后继的后继结点
  • 0:新结点入队时的默认状态
    负值表示结点处于有效等待状态,而正值表示结点已被取消。所以源码中很多地方用>0、<0来判断结点的状态是否正常。
获取成功就直接返回,获取失败就排队去。

public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }
释放成功就看要不要,通知后续节点,释放失败就返回释放失败。

public final boolean release(int arg) {
        if (tryRelease(arg)) {
            Node h = head;
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);
            return true;
        }
        return false;
    }

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/76452.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!