线程
概述
- 进程:应用程序在内存中分配的空间,也就是运行中的程序,各个进程之间互不干扰,进程是操作系统进行资源分配的基本单位,单独占有内存地址空间和其他系统资源
- 线程: 线程是操作系统进行调度(cpu分配时间)的基本单位, 是在进程中执行的一个任务,共享所属进程的内存地址空间和资源
jvm层面线程状态
- 以下状态为虚拟机线程状态,并不映射任何操作系统的线程状态
-
新建状态(NEW): 新创建的线程,还未调用start() 方法
-
可运行状态(RUNNABLE) : 调用了start() 方法,线程已经进入虚拟机,在等待操作系统的其他资源,如IO阻塞,网络阻塞,或者已经在运行中
-
阻塞状态(BLOCKED): 线程需要等待获取锁,等待进入同步(synchronized)方法或者同步块中, 或者说当因为获取不到锁而无法进入同步块时,线程处于 BLOCKED 状态
- 等待状态(WAITING): 当条件不满足时,等待其他线程完成操作使得条件满足,并通知等待中的线程,调用
Object.wait()
,Thread.join()
,LockSupport.park()
方法会使得线程进入等待状态。当一个线程调用Object.wait()
方法时,需要等待其他线程调用Object.notify()
/Object.notifyAll()
方法来唤醒, 当一个线程被 调用LockSupport.park()
方法时,线程进入等待状态,需要对应的LockSupport.unPark(Thread)
方法来唤醒指定的线程,或者通过interrupted()
方法中断线程使得线程继续执行,使得线程继续运行
- 等待状态(WAITING): 当条件不满足时,等待其他线程完成操作使得条件满足,并通知等待中的线程,调用
-
限时等待(TIMED_WAITING): 等待指定的时间,调用
Thread.sleep
,Object.wait(long)
,Thread.join(long)
等方法会让线程进入该状态 -
结束状态(TERMINATED) : 线程执行完毕或者退出
操作系统层面的线程状态
- 操作系统层面的线程状态主要围绕cpu 操作
- new : 新建一个线程
- ready: 进入就绪状态,获得了除cpu 外的其他资源
- running : 运行状态, 线程已在cpu 上执行
- waiting : 等待状态,由于I/O ,或者其他等待事件,使得线程放弃cpu资源,从而进入等待状态,在这些事件完成后,线程会从新进入ready 状态,等待cpu资源的分配
- terminated : 线程执行完成
重要方法
-
Object.wait
-
wait方法调用前需要获得锁, 应该总是在 循环中调用,即条件判断应该放在循环的条件判断,而不是放在 if 的判断中,防止虚假幻想(幻想后任然不符合执行条件)
synchronized (obj) { while (<condition does not hold>) obj.wait(timeout); ... // Perform action appropriate to condition }
-
wait 方法必须在同步方法或者同步块中
synchronized
,即要先获取锁才能调用wait 方法,这是第一次enter -
当前线程调用 wait方法后会释放 锁,当前线程进入该锁的 等待队列中,当前线程进入等待状态
WAITING
-
当收到其他线程的 notify 或者 notifyAll 通知后,当前线程并不能立即恢复执行,因为他已经释放了锁,所以要重新执行wait方法后的代码需要重新获取 锁,再次进入同步块中 这是第二次进入(reenter)
-
-
Thread.join
- 有线程a,b , 在线程 a 中调用 b.join , 相当与让 a线程等待 b线程的完成 , 此时a 停止执行, 等b执行完了,会通知a线程,使其恢复执行
-
Thread.sleep
- 经常会听到说 wait方法会释放锁, sleep 方法不会释放锁,其实这句话是不准确的,sleep 方法与锁无关,执行sleep 方法前并不是一定要获取锁(执行wait 方法前一定要先获取锁), 如果执行sleep 方法时没未获取锁,也就无所谓释放不释放,如果执行sleep 方法时已经获取了锁,则不会释放锁
-
Thread.yield()
- 中断当前线程的执行,让出cpu, 让自己和其他线程重新竞争cup 资源并运行
-
LockSupport.park()
-
使得当前线程停止执行进入等待状态,当调用
LockSupport.unPark(Thread)
方法指定解锁该线程时,线程继续从中断处运行,或者该线程调用了interrupt()
方法中断该线程时,也会使得线程结束等待状态,继续运行public class LockSupportTest { public static class ParkThread extends Thread{ public ParkThread(String name) { super(name); } @Override public void run() { System.out.println(getName() + " running 00000000"); LockSupport.park(); if (Thread.currentThread
-