Java多线程
文章目录
-
- Java多线程
-
- 1、什么是死锁?怎么避免死锁?
- 2、说下sleep()方法和wait()方法区别?
- 3、调用start()方法时会执行run()方法,为什么我们不能直接调用run()方法呢?
- 4、说一下你对于synchronized关键字的理解
- 5、synchronized关键字怎么使用?
- 6、写个单例模式
- 7、说一下JMM(Java内存模型)
- 8、说说 synchronized 关键字和 volatile 关键字的区别
- 9、说一下ThreadLocal
- 10、创建线程的几种方式
- 11、实现Runnable接口和Callable接口的区别?
- 12、线程池的种类有哪些?
- 13、线程池ThreadPoolExecutor的饱和策略
- 14、线程池的阻塞队列
- 15、线程池构建时的7大参数(重点):
- 16、线程池的底层工作流程(重点):
- 17、Java中用到的线程调度算法是什么?
- 18、线程的调度策略
- 19、线程同步及线程调度相关方法
- 20、你是如何使用wait()方法的,放if块内还是放循环内?为什么?
- 21、Thread类中的yield()方法有什么用?
- 22、为什么Thread类的sleep()和yield()方法是静态的?
- 23、sleep()和yield()方法有什么区别?
- 24、Java中interrupted()和isInterrupted()方法的区别?
- 25、notify()和notifyAll()有什么区别?
- 26、如何在两个线程间共享数据?
- 27、如果你提交任务时,线程池的阻塞队列已满,这时会发生什么?
- 28、Java中如何保证多线程安全?
- 29、Thread类的构造方法、静态代码块是被哪个线程调用的?
- 30、Java中如何获取一份线程dump文件?
- 31、Java内存模型
- 32、如果一个对象的引用被置为null,是否会被GC立即回收?
- 33、什么是重排序?
- 34、synchronized可重入锁原理
- 35、什么是自旋?
- 36、多线程中synchronized锁升级的原理?
- 37、线程A怎么知道线程B修改了变量?
- 38、synchronized、volatile、CAS比较
- 39、synchronized和Lock有什么区别?
- 40、volatile关键字的作用?
- 41、volatile变量和atomic变量有什么不同?
- 42、什么是悲观锁和乐观锁?
- 43、什么是CAS?
- 44、CAS会产生什么问题?
- 45、什么是原子类?
- 46、原子类的常用类
- 47、什么是线程组,在Java中推荐使用吗?
- 48、你经常使用什么并发容器?为什么?
- 49、CopyOnWriteArrayList是什么?
- 50、CopyOnWriteArrayList的设计思想?
- 51、常用的并发工具类有哪些?
1、什么是死锁?怎么避免死锁?
死锁:是指多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放,由于线程被无限期地阻塞,程序不能终止陷入死锁。
避免死锁:(1)一次性申请完所有资源;(2)占用部分资源的线程进一步申请其他资源时,如果申请不到,主动释放掉它占有的资源;(3)按照某个顺序申请资源。
2、说下sleep()方法和wait()方法区别?
两者都可以暂停线程的执行。
(1)sleep()是Thread类的静态方法,wait()是Object类的方法;
(2)sleep()方法没有释放锁,而wait()方法释放了锁;
(3)wait()方法通常被用于线程之间的通信交互,sleep()方法通常被用于暂停某个线程的执行;
(4)wait()方法执行后,线程不会自动苏醒,需要别的线程调用同一个对象上的notify()或者notifyAll()方法。sleep()方法执行完成后,线程会自动苏醒。或者可以使用wait(long timeout)超时等待后线程会自动苏醒。
3、调用start()方法时会执行run()方法,为什么我们不能直接调用run()方法呢?
new一个Thread对象时,线程进入了新建状态。调用start()方法,会启动一个线程并使线程进入了就绪状态,当分配到时间片后就可以开始运行了。start()会执行线程的相应准备工作,然后执行run()方法的内容,这才是真正的多线程工作。
如果直接执行run()方法,会把run()方法当成一个main线程下的普通方法去执行,并不会在某个线程中去执行它,所以这并不是多线程工作。
4、说一下你对于synchronized关键字的理解
synchronized是一个关键字,可以保证修饰的方法或者代码块在同一时刻只能有一个线程执行。
在Java早期版本,synchronized属于重量级锁,效率低下。因为监视器锁(monitor)依赖底层操作系统的Mutex Lock来实现的,无论挂起或者唤醒线程,都需要操作系统帮忙,而操作系统实现线程之间的切换需要花费较长时间,成本较高。
Java6之后官方从JVM层面对synchronized有很大的优化,还引入了很多锁技术,如自旋锁、锁消除、锁粗化、偏向锁、轻量级锁等。所以,你会发现目前,不论各种框架还是jdk源码都大量使用了synchronized关键字。
5、synchronized关键字怎么使用?
(1)修饰实例方法:锁住当前对象,调用方法时,要获得当前对象实例的锁。
(2)修饰静态方法:锁住当前类,作用于类的所有对象实例,调用方法时,要获得当前class的锁,因为静态方法属于类级别的。
(3)修饰代码块:自定义加锁对象,给指定对象/类加锁。
总结:
synchronized加到static静态方法和synchronized(xx.class)都是给Class上锁;
synchronized加到实例方法是给对象实例上锁;
尽量不要使用synchronized(String a),因为JVM中,字符串常量池具有缓存功能。
6、写个单例模式
(1)饿汉式:jdk源码Runtime类,线程安全
public class Runtime {
private static Runtime currentRuntime = new Runtime();
public static Runtime getRuntime() {
return currentRuntime;
}
private Runtime() {
}
}
(2)懒汉式:线程安全
public class Singleton {
private static Singleton instance;
private Singleton() {
}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
(3)使用双重校验 + volatile:线程安全
public class Singleton {
private static volatile Singleton instance = null;
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null) {
// 先判断实例是否存在,不存在再加锁
synchronized (Singleton.class