线程的创建与启动
Java中,所有的线程对象都必须是Thread类或其子类的实例。
三种创建方式:
-
集成Thread类创建线程类
继承Thread类,重写run方法,run方法的方法体代表线程需要完成的任务,称为线程执行体。
创建子类的实例,即创建了线程对象。
调用线程对象的start方法就可以启动了该线程。
class ThreadChild1 extends Thread { @Override public void run() { super.run(); //... } } private static void main(String[] args){ //启动一个线程 new ThreadChild1().start(); //启动第二个线程 new ThreadChild1().start(); }
-
实现Runnable接口创建线程类
实现Runnable接口,重写run方法,也是线程方法执行体。
创建实现类的实例,将实例作为参数传到Thread构造函数中,可创建Thread线程对象
class ThreadChild1 implements Runnable{ @Override public void p run() { //... } } private static void main(String[] args){ ThreadChild1 threadChild1 = new ThreadChild1(); //启动一个线程 new Thread(threadChild1, "first").start(); //启动第二个线程 new Thread(threadChild1, "second").start(); }
-
使用Callable和Future创建线程
创建Callable接口的实现类,重写call方法,call方法有返回值,再创建Callable实现类的实例。
创建FutureTask实例传入Callable对象。
再将FutureTask实例作为参数传到Thread构造函数中,可创建Thread线程对象。
通过FutureTask实例对象调用get()方法得到子线程的返回值。
class ThreadChild1 implements Callable<Integer> { @Override public Integer call() throws Exception { //... } } private static void main(String[] args){ ThreadChild1 child1 = new n ThreadChild1(); FutureTask<Integer> task = new n FutureTask<>(child1); new Thread(task, "有返回值的线程").start(); //获取子线程的返回值 try { System.out.println("子线程的返回值: "+futureTask.get()); } catch (Exception e) { e.printStackTrace(); } }
一般推荐实现接口创建多线程,直接继承Thread后,无法再继承其他父类。
线程的生命周期
线程被创建并启动后,会经历五种状态。
新建new->就绪runnable->运行running->阻塞blocked->死亡dead
新建:
XxxThread xx = new XxxThread()
就绪:
调用start后,线程处于就绪状态,此时已经做好了执行的准备,可以运行了,但还没有运行,蓄势待发。
运行:
线程获得调度时,线程处于运行状态,开始执行run方法中的线程执行体。
阻塞:
线程处于活动状态,但是停止运行,没有CPU的使用权。
**1. 等待阻塞:**线程调用wait方法;调用join方法,等待别的线程终止或超时后执行本线程。
**2. 同步阻塞:**线程获取锁失败,会进入同步阻塞状态。
**3. 其他阻塞:**调用线程的sleep方法,等sleep完毕,转入就绪;发出I/O请求,请求处理完毕,线程转入就绪状态。
死亡:
退出run方法时,线程会自然死亡。
图解: