一、说说你在平时的开发中,如何使用线程池?
解答:此题目看似非常广泛,无从着手。但其实不然,面对这样的题目,可以从自己熟悉的知识点着
手。例如:
平时使用线程池时,一般使用 new ThreadPoolExecutor 的方式去创建线程池,再联系到这种方式的运行机制:
通过new创建线程池时,除非调用prestartAllCoreThreads方法初始化核心线程,否则此时线程池中有0个线程,即使工作队列中存在多个任务,同样不会执行
1:当任务数<=核心线程数的时候,会创建于当前任务数相同的核心线程用于处理线程
2:当当前任务数 >= 核心线程数&& 当前任务数 < 工作队列容量 + 核心线程数 会启动设定的核心
线程数个线程 其他的任务就放到工作队列里
3: 当前任务数 > 工作队列容量+核心线程数的容量时,分两种情况
当当前任务数 - 工作队列容量 <= 最大线程数 ,此时启动 (当当前任务数 - 工作队列容量)个线程
当当前任务数 - 核心线程数-工作队列容量 > 最大线程数,会启动最大线程数数量的线程来处理
二、说说sleep与wait的区别
wait只能在同步块(synchronize)环境中被调用,而sleep不需要。
wait方法在进入wait状态的时候会释放对象的锁,但是sleep方法不会。
进入wait状态的线程能够被notify和notifyAll线程唤醒,但是进入sleeping状态的线程不能被
notify
三、说说Synchronize关键字的用法
synchronize关键之可以用于修饰普通方法、静态方法以及普通代码块,分别锁住的是:
修饰普通方法:锁住对象的实例(new 出多少个对象,各个对象之间不会相互竞争)
修饰静态方法:锁住整个类(new 出多少个对象,各个对象之间会相互竞争)
修饰代码块: 锁住一个对象 synchronized (object) 即synchronized后面括号里的对象
四、说说Synchronized与Lock的区别
synchronized的锁可重入、不可中断、非公平,每次使用会自动释放锁
Lock锁可重入、可中断、可公平,每次使用需要自己加锁以及释放锁,一般情况下需放在fifinally
里进行锁的释放,否则,可能因为未能正确释放锁而导致程序出问题。Lock可以实现有限时间内
的获取锁的等待,在指定的时间内如果获取不到锁,会返回false
此处,如果是熟悉ReentrantLock或者ReentrantReadWriteLock源码的同学,可以往底层原理延 伸,例如讲到Lock可以公平的时候,可以延伸到底层源码中是如何实现锁的公平性的
五、说说volatile关键字
当一个变量使用 volatile修饰之后,将具备两种特性:保证此变量对所有的线程的可见性;禁止指
令重排序优化。当volatile修饰普通变量的时候,该变量具有可见性,如果修饰的是一个对象,对
象内部的属性并不具备可见性。volatile仅仅保证变量的修改后的值对于其他线程可见,但是并不
保证其原子性,也就是说:即使变量用volatile关键字修饰,++操作依旧不是线程安全的。
这类题目,再加上具体使用场景,面试官的印象会更好,比如: 在多线程处理任务的时候,使用volatile关键字修饰变量作为开关,保证一个线程对其状态进行修 改之后,其他线程立刻可见并作出反应