1、线程的几种状态
- new:新建一个对象
- 可运行runnable:start使得线程位于可运行线程池中,等待被调度
- 运行running:runnable的线程获得了时间片
- 阻塞block:
- 等待阻塞:running线程执行wait,JVM把线程放进等待队列
- 同步阻塞:running在获取对象同步锁时,同步锁被其他线程占用,JVM把该线程放进锁池
- 其他阻塞:running执行sleep、join、发出IO请求
- 死亡dead:run执行结束/main结束/因异常退出run/线程结束生命周期
2、死锁以及如何避免
- 死锁:两个以上的线程杨院长阻塞的情况。
- 死锁的四个必要条件:
互斥条件:
请求与保持条件:
不可剥夺条件:
循环等待条件:
- 死锁的避免:
加锁顺序(线程按照一定的顺序加锁)
加锁时限(线程尝试获取锁的时候加上一定的时限,超过时限则放弃对该锁的请求,并释放自己占有的锁)
死锁检测:
3、ThreadLocal
ThreadLocal中填充的变量属于当前线程,该变量对其他线程而言是隔离的。ThreadLocal为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量。
1、管理Connection
最典型的是管理数据库的Connection:当时在学JDBC的时候,为了方便操作写了一个简单数据库连接池,需要数据库连接池的理由也很简单,频繁创建和关闭Connection是一件非常耗费资源的操作,因此需要创建数据库连接池~
那么,数据库连接池的连接怎么管理呢??我们交由ThreadLocal来进行管理。为什么交给它来管理呢??ThreadLocal能够实现当前线程的操作都是用同一个Connection,保证了事务!
2、避免一些参数传递
4、线程饿死?线程活锁?
- 活锁:两个线程互相修改对方的结束条件导致它们谁也结束不了。
- 饿死:我们知道多线程执行中有线程优先级这个东西,优先级高的线程能够插队并优先执行,这样如果优先级高的线程一直抢占优先级低线程的资源,导致低优先级线程无法得到执行,这就是饥饿。当然还有一种饥饿的情况,一个线程一直占着一个资源不放而导致其他线程得不到执行,与死锁不同的是饥饿在以后一段时间内还是能够得到执行的,如那个占用资源的线程结束了并释放了资源。
5、同步集合和并发集合
同步集合会把整个Map或List锁起来,而并发集合不会。并发集合实现线程安全是通过使用先进的和成熟的技术像锁剥离。
6、interrupted和isInterrupted
interrupted() 和 isInterrupted()的主要区别是前者会将中断状态清除而后者不会。Java多线程的中断机制是用内部标识来实现的,调用Thread.interrupt()来中断一个线程就会设置中断标识为true。当中断线程调用静态方法Thread.interrupted()来检查中断状态时,中断状态会被清零。
非静态方法isInterrupted()用来查询其它线程的中断状态且不会改变中断状态标识。
7、实现线程
1、继承Thread
1)定义一个继承自Java.lang.Thread类的类A.
2):覆盖A类Thread类中的run方法。
3):我们编写需要在run方法中执行的操作:run方法中的代码,线程执行体。
4):在main方法(线程)中,创建一个线程对象并启动线程。
2、实现Runnable接口
1):定义要在java.lang.Runnable接口中实现的类A.请注意,A类不是线程类。
2):覆盖A类Runnable接口中的run方法。
3):我们编写需要在run方法中执行的操作:在run方法中,线程执行。
4):在main方法(线程)中,创建一个线程对象并启动线程。
8、sleep vs. wait
- sleep()方法是线程类(Thread)的静态方法,wait()方法是Object类里的方法。
- 调用sleep时不需要持有锁,即sleep方法可在任意地方使用。若执行sleep时线程处于上锁状态,sleep并不会释放锁,只会让出CPU时间片;
- 当sleep休眠时间满后并不会立即执行(可能未获得时间片)
- sleep必须捕获异常
- wait()是Object类里的方法,当一个线程执行wait时,进入到一个和该对象相关的等待池中,同时释放对象锁,让出时间片
- 使用notify/notifyAll只是激活线程,需要再次获得锁才能继续往下运行。
- wait只能在同步方法或者同步块中使用;
9、sleep vs. yield
-
sleep()方法给其他线程运行机会时不考虑线程的优先级,因此会给低优先级的线程以运行的机会;yield()方法只会给相同优先级或更高优先级的线程以运行的机会;
-
线程执行sleep()方法后转入阻塞(blocked)状态,而执行yield()方法后转入就绪(ready)状态
-
sleep()方法声明抛出InterruptedException,而yield()方法没有声明任何异常;
-
sleep()方法比yield()方法(跟操作系统CPU调度相关)具有更好的可移植性。