淘先锋技术网

首页 1 2 3 4 5 6 7

线程的六种状态和线程池的使用

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( ) :
  1. 在哪一个线程中执行了,就会让当前所在的线程进入无限等待状态。
  2. wait()方法会打开锁对象,将由其它线程占据锁对象执行。
  • public void notify( ) :
  1. 随机唤醒一个和当前锁对象有关的无限等待状态下的线程。
  2. 开启锁对象。
  • public void notifyAll( ) :
  1. 唤醒和当前锁对象有关的无限等待状态下所有线程。
  2. 开启锁对象,所有线程对象进入一个抢占过程,当某一个线程对象抢占到锁对象后,其它线程进入锁阻塞BLOCKED状态。
    在这里插入图片描述
1.5 TIME_WAITING-计时等待
  • 当前线程的确是等待状态,但是会在一定时间之后自动回到RUNNABLE状态,可通过Thread.sleep(int ms)或者Object类当中的wait(int ms)方法进入计时等待状态。
  • Thread.sleep(int ms) :
  1. 在当前线程代码块中,当前线程休眠指定的毫秒数。
  2. sleep方法必须执行在当前线程的run方法内,才可以休眠线程。
  3. 当前线程因为sleep方法进入等待状态后,只能等待指定时间过去,无法通过其它线程唤醒,且sleep方法不会打开锁对象。
  • Object类内的wait(int ms) :
  1. 线程进入一个计时等待状态,在等待指定的时间之后,线程回到可执行状态。
  2. 在计时等待状态过程中,被其它线程调用notify()或者notifyAll()方法唤醒。
  3. 当前线程指定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();
	}
}