Java学习打卡-Day22-多线程
线程创建与使用
严格来说,Java就只有一种方式可以创建线程,那就是通过new Thread().start()创建。而所谓的Runnable、Callable……对象,这仅仅只是线程体,也就是提供给线程执行的任务,并不属于真正的Java线程,它们的执行,最终还是需要依赖于new Thread()……
方式一:继承 Thread 类
- 当一个类继承了 Thread 类,就可以把它当做一个线程。
- 一般会重写run()方法,写上自己的业务代码。
- Thread 类中的run()方法实际上是实现了 Runnable 接口中的run()方法。
public class ExtendsThread extends Thread { @Override public void run() { System.out.println("继承Thread类的线程:" + Thread.currentThread().getName()); } public static void main(String[] args) { new ExtendsThread().start();//启动线程 } }
- 当main线程启动一个子线程Thread-0,主线程不会阻塞,会继续执行,且主线程和子线程交替执行。
- start()方法会执行一个start0()方法,调用start0()方法后该线程不一定立马执行,只是将变成了可运行状态。具体什么时候执行,取决于CPU,由CPU统一调度。真正实现多线程效果的是start0(),不是run()。
方式二:实现Runnable 接口
- java是单继承的,在某些情况下一个类可能已经继承了某个父类,这时再用继承
Thread类的方式来创建线程显然不可能了。public class ImplementsRunnable implements Runnable { @Override public void run() { System.out.println("2......"); } public static void main(String[] args) { ImplementsRunnable runnable = new ImplementsRunnable(); new Thread(runnable).start(); } }
- 代理模式:Thread.start()->Thread.start0()->Thread.run()->Thread.target.run()->runnable.run()。这里将runnable作为参数传给了Thread中的target属性。
- 实现 Runnable 接口的方式更加适合多个线程共享一个资源的情况。
未完待续。。。
线程常用方法
setName(String name) //设置线程名称,使之与参数name相同
getName() //返回该线程的名称
start() //使该线程开始执行。Java虚拟机底层调用该线程的start0()方法
run() //调用线程对象run方法;
setPriority(int priority) //更改线程的优先级
getPriority() //获取线程的优先级
sleep(long millisec) //在指定的毫秒数内让当前正在执行的线程休眠(暂停执行)
interrupt() //中断线程,停止休眠
yield() //让出cpu,暂停当前正在执行的线程对象,并执行其他线程。但礼让的时间不确定,所以也不一定礼让成功。
join() //线程的插队。插队的线程一旦插队成功,则肯定先执行完插入的线程所有的任务。
线程终止
- 当线程完成任务后,会自动退出。
- 还可以通过使用变量来控制run()方法退出的方式停止线程,即通知方式。
用户线程与守护线程
- 用户线程:也叫工作线程,任务执行完结束或以通知方式结束。
- 守护线程:一般是为工作线程服务的,当所有的用户线程结束,守护线程自动结束。常见的守护线程:垃圾回收机制。
线程的生命周期
- Java 线程在其生命周期中的任何时刻只可能处于下面 6 种不同状态的其中一个。
- NEW:初始状态,线程被创建出来但没有被调用 start() 。
- RUNNABLE:运行状态,线程被调用了 start()等待运行的状态。
- BLOCKED:阻塞状态,需要等待锁释放。
- WAITING:等待状态,表示该线程需要等待其他线程做出一些特定动作(通知或中断)。
- TIME_WAITING:超时等待状态,可以在指定的时间后自行返回而不是像 WAITING 那样一直等待。
- TERMINATED:终止状态,表示该线程已经运行完毕。