常用方法
start和run
调用run
public static void main(String[] args) { Thread t1 = new Thread("t1") { @Override public void run() { log.debug(Thread.currentThread().getName()); FileReader.read(Constants.MP4_FULL_PATH); } }; t1.run(); log.debug("do other things ..."); }
输出:
19:39:14 [main] c.TestStart - main 19:39:14 [main] c.FileReader - read [1.mp4] start ... 19:39:18 [main] c.FileReader - read [1.mp4] end ... cost: 4227 ms 19:39:18 [main] c.TestStart - do other things ...
程序仍在 main 线程运行, FileReader.read() 方法调用还是同步的
调用start
将上述代码的 t1.run() 改为 t1.start
输出:
19:41:30 [main] c.TestStart - do other things ... 19:41:30 [t1] c.TestStart - t1 19:41:30 [t1] c.FileReader - read [1.mp4] start ... 19:41:35 [t1] c.FileReader - read [1.mp4] end ... cost: 4542 ms
此时再t1线程执行,而FileReader.read() 方法调用是异步的
总结
直接调用run是在主线程中执行了run,并没有启用新的线程,而使用start是启动新的线程,通过新的线程简介执行了run中的代码。
sleep和yield
sleep
**调用 sleep 会让当前线程从 Running 进入 Timed Waiting 状态(阻塞)**以一段代码为例
Thread t1 = new Thread("t1") { @Override public void run() { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } }; t1.start(); System.out.println("t1 state: "+ t1.getState()); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("t1 state: "+ t1.getState());
输出:
t1 state: RUNNABLE t1 state: TIMED_WAITING
其它线程可以使用 interrupt 方法打断正在睡眠的线程,这时 sleep 方法会抛出 InterruptedException
Thread t1 = new Thread("t1") { @Override public void run() { log.debug("enter sleep..."); try { Thread.sleep(2000); } catch (InterruptedException e) { log.debug("wake up..."); e.printStackTrace(); } } }; t1.start(); Thread.sleep(1000); log.debug("interrupt..."); t1.interrupt();
输出:
enter sleep... wake up... java.lang.InterruptedException: sleep interrupted at java.lang.Thread.sleep(Native Method) at test2$1.run(test2.java:10)
睡眠结束后的线程未必会立刻得到执行
睡眠结束,可能还在处理其他的线程,需要等待cpu调度器调度
yield
本质上是让出cpu的使用权, 调用 yield 会让当前线程从 Running 进入 Runnable 就绪状态,然后调度执行其它线程。具体的实现依赖于操作系统的任务调度器
线程优先级
线程优先级会提示(hint)调度器优先调度该线程,但它仅仅是一个提示,调度器可以忽略它
如果 cpu 比较忙,那么优先级高的线程会获得更多的时间片,但 cpu 闲时,优先级几乎没作用
join方法详解
为什么需要join?
下面的代码执行,打印 r 是什么?
log.debug("开始"); Thread t1 = new Thread(() -> { log.debug("开始"); sleep(1); log.debug("结束"); r = 10; },"t1"); t1.start(); // t1.join(); log.debug("结果为:{}", r); log.debug("结束");
分析:
- 因为主线程和线程 t1 是并行执行的,t1 线程需要 1 秒之后才能算出 r=10
- 而主线程一开始就要打印 r 的结果,所以只能打印出 r=0
解决方案:
- 用 sleep 行不行?为什么?不能精准的把控执行结束的时间。
- 用 join,加在 t1.start() 之后即可**(可选)**
以调度的角度来讲,如果
- 需要等待结果返回,才能继续运行就是同步
- 不需要等待结果返回,就能继续运行就是异步
等待多个结果
Thread t1 = new Thread(() -> { sleep(1); r1 = 10; }); Thread t2 = new Thread(() -> { sleep(2); r2 = 20; }); long start = System.currentTimeMillis(); t1.start(); t2.start(); t1.join(); t2.join(); long end = System.currentTimeMillis(); log.debug("r1: {} r2: {} cost: {}", r1, r2, end - start);
分析:
实际上,2s执行完成,为什么呢?因为 两个线程都是同时启动的,无论t1.join 和 t2.join那个在前那个在后,其最终都会对两个线程分别的阻塞等待,只因为两个线程是同时启动的。
所以结果时不变的,效果图如下:
剑指JUC原理-3.线程常用方法及状态(下):https://developer.aliyun.com/article/1413577