一、线程创建的两种主要方式
- 继承thread类:定义一个继承自Thread的子类并重写该类的run()方法,run方法是线程要完成的任务,因此我们称之为执行体
public class RunnableThreadCreate implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
@Test
public void createByRunnable() {
Runnable target = new RunnableThreadCreate();
Thread thread = new Thread(target,"线程一");
thread.start();
System.out.println(Thread.currentThread().getName());
}
- 实现Runnable接口:定义一个实现了Runnable接口的类,将该类的实例作为target传入Thread的构造方法,Thread类的实例才是我们要操作的线程
/**
* @Date 2022/2/14 13:58
* @Author mawkun
*/
public class ThreadCreate extends Thread {
//设置线程名称
public ThreadCreate(String name) {
this.setName(name);
}
@Override
public void run() {
super.run();
System.out.println(Thread.currentThread().getName());
}
}
@Test
public void createByThread() {
ThreadCreate threadCreate = new ThreadCreate("线程一");
threadCreate.start();
System.out.println(Thread.currentThread().getName());
}
比较两种创建线程方式的优劣:
- 实现Runnable接口可以避免java不能多继承的劣势
- 实现Runnable更能体现资源共享的概念,适合相同的代码处理共享的资源
- 增加程序的健壮性,代码和数据分离
- 线程池中只可以放入实现了Runnable或callable接口的线程
二、线程的生命周期
-
新建状态(New) :线程对象被创建后,就进入了新建状态。例如,Thread thread = new Thread()。
-
就绪状态(Runnable) :也被称为“可执行状态”。线程对象被创建后,其它线程调用了该对象的start()方法,从而来启动该线程。例如,thread.start()。处于就绪状态的线程,随时可能被CPU调度执行。
-
运行状态(Running) :线程获取CPU权限进行执行。需要注意的是,线程只能从就绪状态进入到运行状态。
-
阻塞状态(Blocked) : 阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。
阻塞的情况分三种:
- 等待阻塞 -- 通过调用线程的wait()方法,让线程等待某工作的完成。
- 同步阻塞 -- 线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态。
- 其他阻塞 -- 通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
-
死亡状态(Dead)****:线程执行完了或者因异常退出了run()方法,该线程结束生命周期
三、线程状态控制
- start() 启动当前线程,调用当前线程的run()方法
- run() 通常需要重写Thread类中的此方法,将创建的线程要执行的操作声明在此方法中
- yield() 释放当前CPU执行权
- join() 在线程a中调用线程b的join(),此时线程a进行阻塞状态,直到线程b完成执行完以后,线程a结束阻塞
- sleep(long militime) 让线程睡眠指定的毫秒数,在指定时间内,线程是阻塞状态
- wait() 一旦执行此方法,当前线程就会进入阻塞一旦执行wait()会释放同步监听器
- noity() 执行此方法,将会唤醒被wait的一个线程,如果有多个wait状态线程,唤醒优先度最高的
- noityAll() 执行此方法,唤醒所有被wait的线程
sleep和wait比较:
- 相同点:sleep和wait都会让线程进入阻塞状态
- 不同点:
- Thread类中声明sleep(),Object类中声明wait()
- 调用要求不同,sleep()方法可以在任何需要的场景下调用,wait()必须在同步代码块中调用
- 如果两个方法都在同步方法或者同步代码块中使用,sleep不会释放锁,wait会释放锁