1. 进程和线程的区别
- 进程是资源分配的基本单位;线程是任务调度执行的基本单位;
- 进程的创建和销毁消耗的资源都比线程要多;
- 多个进程之间的内存资源是独立的;在一个进程中多个线程之间的内存资源是共享的;
一个进程中包含多个线程,一个线程中包含多个协程。在单线程中有多个协程并发执行,实际上还是串行执行的。
2. 并行和并发的区别
并行是在同一时刻内多条指令在多个处理器中执行,从微观和宏观上看都是并行的;
并发是在同一时刻内只能有一条指令执行,从宏观上是并行的,从微观上是串行的,只是把时间分成若干段,使每个进程之间快速交替执行。
3. Java 中怎么创建线程
- 继承 Thread 类,重写 run 方法(run中逻辑就是线程要执行的工作,只有当子类实例化,调用start方法时,才可以真正创建线程)
- 实现 Runnable 接口,重写 run 方法(创建了Runnable实例,将runnable实例作为参数传给线程,将线程要干的工作 和 线程本身 分开,使用Runnable来专门表示“线程要完成的工作”,这种方法的好处是,降低了耦合性,如果以后要修改代码,改动相对较少,只需要将修改后的Runnable传给其他的实体就可以了)
- 使用匿名内部类实现(创建Thread子类的方式或实现Runnable接口的方法)
- 实现 Callable 接口,并结合 Future 实现(很少用)
-
通过线程池创建线程(创建 Runnable 的实现类,重写 run 方法,然后创建一个拥有固定线程数的线程池,最后通过 ExecutorService 对象的 execute 方法传入线程对象)
4. 常见操作线程的方法
- 启动线程:start
- 中断线程:isInterrupted(线程中断,本质上是让run方法尽快结束,而不是run执行一半,强制结束)
- 等待线程:join
-
获取当前线程引用:currentThread(); 获取到当前这个线程对应的Thread对象的引用
5. 线程状态
新建(new)-就绪(runnable)-运行(running)-阻塞(block)-死亡(dead)
- new:安排了工作,还未开始行动(Thread对象创建完成,但内核PCB还没创建);
- runnable:可工作的,又可以分成正在工作(正在CPU上运行)和即将开始工作(就绪状态:在就绪队列中排队)
- blocked:等待状态(等待锁的时候进入阻塞状态Synchronized)
- waiting:等待状态(特殊的阻塞状态,调用wait)
- timed_waiting:等待状态(按照一定的时间进行阻塞Sleep)
- terminated:工作完成(内核PCB销毁,但是Tread对象还在)
6. 线程不安全的原因
- 操作系统调度执行的随机性,抢占式执行
- 多个线程修改同一个变量
- 修改操作不是原子的(解决线程安全最常见的方法:加锁Synchronized)
- 内存可见性(内存可见性属于是JVM的代码优化引入的bug)
- 指令重排序
7. Synchronized 和 ReentrantLock 的区别
- 用法不同,Synchronized 可以用来修饰普通方法、静态方法和代码块,而 ReentrantLock 只能用于代码块;
- 锁类型不同,Synchronized 是非公平锁,而 ReentrantLock 默认为非公平锁,也可以手动指定为公平锁(构造时传入一个参数true,就成了公平锁)
- 获取锁和释放锁的机制不同:synchronized是自动加锁和释放锁的(搭配 wait/ notify 实现等待通知机制,唤醒操作时随机唤醒一个等待进程),而 ReentrantLock 需要手动加锁和释放锁(tryLock试试加锁能不能成功,如果失败了,就等待一定时间后就放弃加锁。使用Condition可以将唤醒操作指定唤醒哪个等待的线程的)
- 响应时间不同:ReentrantLock 可以响应中断(加超时时间),解决死锁问题,而 synchronized 不能响应中断
- 底层实现不同:synchroized 是JVM 层面通过监视器实现的,而 ReentrantLock 是基于AQS 实现的
8. Volatile 是什么
volatile 是一种关键字,用于保证多线程情况下共享变量的可见性。当一个变量被声明为 volatile 时,每个线程在访问该变量时都会立即刷新其本地内存(工作内存)中该变量的值,确保所有线程都能读到最新的值。并且使用 volatile 可以禁止指令重排序,这样就能有效的预防,因为指令优化(重排序)而导致的线程安全问题。
也就是说 volatile 有两个主要功能:保证内存可见性和禁止指令重排序。
9. wait 和 notify 的作用
作用:协调多个线程的执行顺序
wait操作本质上三步走
(1)释放当前锁,保证其他线程能够正常往下进行(前提是得加了锁。才能释放)
(2)进行等待通知(前提是先要释放锁)
(3)满足一定条件的时候(别的线程调用notify),被唤醒,然后尝试重新获取锁
notify是包含在synchronized里面的
线程1没有释放锁的话,线程2也就无法调用到notify(因为锁阻塞等待)
线程1调用wait,在wait里面就释放了锁,这个时候虽然线程1代码阻塞在synchronized里面
但是此时锁还是释放状态,线程2能拿到锁
10. 线程池怎么创建,里面的参数都有啥
使用标准库中的线程池 ExecutorService,里面的参数都有:
-
核心线程数(corePoolSize):相当于正式工,只要核心线程创建好后,就不会被回收,也就是核心线程数不变
-
最大线程数(maximumPoolSize):相当于正式工+临时工,任务多的时候,正式工忙不过来(核心线程数已满),就多招几个临时工,这个是动态调整的;
-
空闲线程存活时间(KeepAliveTime):线程等待新任务的最大时间
-
空闲线程存活时间单位(unit):时间单位
-
任务队列(workQueue):队列中存放当前等待要执行的任务,任务队列有4中:
-
ArrayBlockingQueue:基于数组的有界阻塞队列;
-
LinkedBlockingQueue:基于链表的无界阻塞队列:
-
SynchronizedQueue:加锁后的队列,也就是不缓存任务的阻塞队列;
-
PriorityBlockingQueue:优先级的无界阻塞队列;
-
-
线程的创建策略(threadFactory):创建一个新线程时使用的工厂,可以用来设定线程名等
-
线程池的拒绝策略(handler):表示当队列慢了并且工作线程>= 线程池最大线程数时如何处理
-
AbortPolicy:丢弃任务并抛出异常;
-
DiscardPolicy:丢弃任务,但不抛出异常;
-
DiscardOldestPolicy:丢弃队列中最前面的任务,然后重新提交被拒绝的任务。
-
CallerRunsPolicy:由调用线程处理该任务;
-
11. 线程池的优点
(1)降低资源消耗:通过重复利用已创建的线程来执行任务,降低线程创建和消耗造成的消耗
(2)提高响应速度:因为省去了创建线程这一步,所以当拿到任务时,可以立即开始执行
(3)提高线程的可管理性:我们可以自己加入新的功能,比如说定时、延时来执行某些线程,也可以监控线程,控制最大并发线程数等功能
12. 说一下死锁的概念
死锁就是,一个线程加上锁之后,解不开了,一直在等待着。
多个线程被同时阻塞了,它们中个一个或多个线程都在等待某个资源被释放。由于线程被无期限的阻塞,因此程序不能正常终止。
发生死锁的四个条件:
不可抢占、请求和保持、互斥使用、循环等待
这里有一个死锁的经典模型就是哲学家就餐问题。
12. 常见的锁策略
http://t.csdnimg.cn/Z9eAf
13. 线程池如何执行?拒绝策略有哪些
线程池的执行流程有 3 个重要的判断点(判断顺序依次往后):判断当前线程数和核心线程数、判断当前任务队列是否已满、判断当前线程数是否已达到最大线程数。如果经过以上 3 个判断,得到的结果都会 true,则会执行线程池的拒绝策略。
当任务过多且线程池的任务队列已满时,此时就会执行线程池的拒绝策略,线程池的拒绝策略默认有以下 4 种:
- AbortPolicy:中止策略,线程池会抛出异常并中止执行此任务;
- CallerRunsPolicy:把任务交给添加此任务的(main)线程来执行;
- DiscardPolicy:忽略此任务,忽略最新的一个任务;
- DiscardOldestPolicy:忽略最早的任务,最先加入队列的任务。
默认的拒绝策略为 AbortPolicy 中止策略。
14. 线程池的底层工作原理
线程池的底层是基于线程和任务队列来实现的,创建线程池的创建方式通常有以下两种:
- 普通 Java 项目,使用 ThreadPoolExecutor 来创建线程池(ExecutorService)
- Spring 项目中,会使用代码可读性更高的 ThreadPoolTaskExecutor 来创建线程池,虽然它的底层也是通过 ThreadPoolExecutor 来实现的,但 ThreadPoolTaskExecutor 可读性更高,因为它不需要在构造方法中设置参数,而是通过属性设置的方式来设置参数的,所以可读性更高。
15. 什么是CAS
CAS(比较并交换)是一种轻量级的同步操作,也是乐观锁的一种实现,它用于实现多线程环境下的并发算法。CAS 操作包含三个操作数:内存位置(或者说是一个变量的引用)、预期的值和新值。如果内存位置的值和预期值相等,那么处理器会自动将该位置的值更新为新值,否则不进行任何操作。
16. 什么是 ABA 问题如何解决
http://t.csdnimg.cn/GDVz6