线程的六种状态和线程池的使用
1. 线程的六种状态
1.1 NEW-新建
- 线程刚刚被创建,还没有调用start方法,没有启动。
1.2 RUNNABLE-可运行
- 线程已经可以在JVM当中运行,但是是否可以运行不确定,看当前线程是否拥有CPU执行权。
1.3 BLOCKED-锁阻塞
- 当前线程进入了一个同步代码块,需要获取对应的锁对象,但是发现当前锁对象已经被其它线程持有,那么当前线程会进入BLOCKED锁阻塞状态,如果占用锁对象的线程打开锁对象,当前线程可能会进入RUNNABLE状态,也可能继续在BLOCKED状态,需要看该线程能否抢占到锁对象。
1.4 WAITING-无限等待
- 通过执行一个wait()方法,线程进入一个无限等待状态,需要另外一个线程进行唤醒操作,进入无限等待的线程是无法自己回到RUNNABLE状态的,需要其他线程通过notify()或者notifyAll()方法进行唤醒操作。
- public void wait( ) :
- 在哪一个线程中执行了,就会让当前所在的线程进入无限等待状态。
- wait()方法会打开锁对象,将由其它线程占据锁对象执行。
- public void notify( ) :
- 随机唤醒一个和当前锁对象有关的无限等待状态下的线程。
- 开启锁对象。
- public void notifyAll( ) :
- 唤醒和当前锁对象有关的无限等待状态下所有线程。
- 开启锁对象,所有线程对象进入一个抢占过程,当某一个线程对象抢占到锁对象后,其它线程进入锁阻塞BLOCKED状态。
1.5 TIME_WAITING-计时等待
- 当前线程的确是等待状态,但是会在一定时间之后自动回到RUNNABLE状态,可通过Thread.sleep(int ms)或者Object类当中的wait(int ms)方法进入计时等待状态。
- Thread.sleep(int ms) :
- 在当前线程代码块中,当前线程休眠指定的毫秒数。
- sleep方法必须执行在当前线程的run方法内,才可以休眠线程。
- 当前线程因为sleep方法进入等待状态后,只能等待指定时间过去,无法通过其它线程唤醒,且sleep方法不会打开锁对象。
- Object类内的wait(int ms) :
- 线程进入一个计时等待状态,在等待指定的时间之后,线程回到可执行状态。
- 在计时等待状态过程中,被其它线程调用notify()或者notifyAll()方法唤醒。
- 当前线程指定wait方法后,会打开锁对象,也就是说其它的线程可以执行。
1.6 TERMINATED-被终止
- 因为run方法运行结束正常退出线程,或者说在运行的过程中因为出现异常,导致当前线程GG思密达。
1.7 六种状态图例
2. 线程池
2.1 为什么要使用线程池
- 不管是继承Thread类还是遵从Runnable接口,都需要重写run方法,而且每一个线程对象有且只能指定一次,之后就会被销毁,线程池就是一个可以容纳多个线程的容器,程序可以从线程池中获取线程来完成目标代码,同时用完之后可以将线程归还给线程池,省去了创建线程和销毁线程的这样非常繁琐的操作,提高了效率,省去了空间。
2.2 线程池的使用
- 方法:
public static ExecutorService newFixedThreadPool(int nThreads):得到一个线程池对象,初始化参数要求当前线程池当中的线程个数。
public Future submit(Runnable target):从线程池中获取一个线程对象,并且执行给定的Runnable接口实现类对象中的目标代码。
class MyThread implements Runnable {
@Override
public void run() {
System.out.println("Runnable接口实现类,线程目标代码");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "hello");
}
}
public class Demo1 {
public static void main(String[] args) {
// 1.得到一个线程池对象
ExecutorService pool = Executors.newFixedThreadPool(5);
// 2.得到一个Runnable接口实现类对象
MyThread myThread = new MyThread();
// 3.使用线程池对象中的一个线程,指定目标代码
// 这里使用的是已经存在的5个线程,初始化线程数为5
pool.submit(myThread);
pool.submit(myThread);
pool.submit(myThread);
pool.submit(myThread);
pool.submit(myThread);
// 因为上面已经使用了线程池中的5个线程,所以
// 下面的会等待上面的线程执行完目标代码之后
// 空闲线程来执行下面的目标代码
pool.submit(myThread);
pool.submit(myThread);
// 4. 关闭线程池
// 一般不用关闭线程池,会随着程序的退出而关闭
pool.shutdown();
}
}