多线程是为了提高CPU的处理效率,也即提高程序的执行效率而引进的。因为在操作系统中CUP,内存,硬盘(IO设备)3者之间存在处理速度上的显著差异这是硬件层面无法解决的矛盾。CPU的处理速度>内存>硬盘(IO设备),为了平衡和内存之间速度差异cpu中引入了缓存,为了能分时复用cpu引入了多线程。
多线程常用的实现方式有,继承Thread类和实现Runnable接口。
在单条件(condition)场景下实现线程的互斥和同步,可以使用synchronized,wait(),notify(),notifyAll()等来实现,在需要线程互斥访问资源的地方使用synchronized修饰,线程间同步也即线程间如何通信的可以利用,wait(),notify(),notifyAll() 例如当某个条件不满足时:while(条件不满足){
Thread.wait();
}
当条件满足时利用notify或者notifyAll,通知线程。如果没有特殊要求的场景,推荐使用notifyAll来进行线程的唤醒,notify唤醒可能有些线程永远没有机会唤醒。
Thread.join(),该方法的意思是,在主线程中执行这个方法会让主线程阻塞来等待子线程执行完才进行下一步操作,并且主线程可以看到子线程对与某些共享变量的操作。比如在某个场景下,有3个资源需要利用3个线程分别去获取,主线程利用各个子线程的join()方法来等待子线程执行完相应的资源获取功能。
volatile 关键字是为了在多线程场景下,对同一个变量读写的可见性,他会告诉编译器对这个变量的读写不能使用cpu缓存,而必须使用内存。
java中线程的生命周期:
1.NEW(初始化状态)
2.RUNNABLE(可运行 / 运行状态)
3.BLOCKED(阻塞状态)
4.WAITING(无时限等待)
5.TIMED_WAITING(有时限等待)
6.TERMINATED(终止状态)
状态可以简化为上图
在java.util.concurrent包中包含了很多多线程处理的工具类,下面我来简单介绍下:
1.Lock ,Condition
Lock支持多个特性:1.能够响应中断,2.支持超时,3.非阻塞地获取锁
// 支持中断的API
void lockInterruptibly()
throws InterruptedException;
// 支持超时的API
boolean tryLock(long time, TimeUnit unit)
throws InterruptedException;
// 支持非阻塞获取锁的API
boolean tryLock();
使用范式:
lass X {
private final Lock rtl = new ReentrantLock(); int value;
public void addOne() {
// 获取锁 rtl.lock(); try { value+=1; } finally { // 保证锁能释放 rtl.unlock(); } }
}
condition :条件变量,在MESA管程模型中条件变量有自己的条件变量队列,管程实现了对共享变量的互斥和同步操作,当某个线程想要对共享变量V执行操作时,可能有两个条件变量A,B相应的会有两个条件变量队列。