* 首先调用该线程的{@code checkAccess}方法,不带任何参数。这可能会导致抛出{@code SecurityException} 。 *
* 否则,此线程的优先级设置为指定的{@code newPriority}和线程的线程组的最大允许优先级中的较小者。 * * @param newPriority 将此线程设置为的优先级 * @throws IllegalArgumentException If the priority is not in the * range {@code MIN_PRIORITY} to * {@code MAX_PRIORITY}. * @throws SecurityException if the current thread cannot modify * this thread. * @see #getPriority * @see #checkAccess() * @see #getThreadGroup() * @see #MAX_PRIORITY * @see #MIN_PRIORITY * @see ThreadGroup#getMaxPriority() */ public final void setPriority(int newPriority) { ThreadGroup g; checkAccess(); if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) { throw new IllegalArgumentException(); } if((g = getThreadGroup()) != null) { if (newPriority > g.getMaxPriority()) { newPriority = g.getMaxPriority(); } setPriority0(priority = newPriority); } } ``` **测试优先级和yield** ```java @Slf4j(topic = "c.TestYield") public class TestYield { public static void main(String[] args) { Runnable task1 = () -> { int count = 0; for (;;) { System.out.println("---->1 " + count++); } }; Runnable task2 = () -> { int count = 0; for (;;) { // Thread.yield(); System.out.println(" ---->2 " + count++); } }; Thread t1 = new Thread(task1, "t1"); Thread t2 = new Thread(task2, "t2"); t1.setPriority(Thread.MIN_PRIORITY); t2.setPriority(Thread.MAX_PRIORITY); t1.start(); t2.start(); } } ``` **运行结果** ``` ...... #优先级 ---->1 283500 ---->2 374389 #yield ---->1 119199 ---->2 101074 ...... ``` > 结论:可以看出,线程优先级和yield会对线程获取cpu时间片产生一定影响,但不会影响太大。 **面试题** **Thread 类中的 yield 方法有什么作用?** yield()应该做的是让当前运行线程回到可运行状态,以允许具有相同优先级的其他线程获得运行机会。因此,使用yield()的目的是让相同优先级的线程之间能适当的轮转执行。但是,实际中无法保证yield()达到让步目的,因为让步的线程还有可能被线程调度程序再次选中。 > 结论:yield()从未导致线程转到等待/睡眠/阻塞状态。在大多数情况下,yield()将导致线程从运行状态转到可运行状态,但有可能没有效果。 **Thread.sleep(0)的作用是什么?** 由于 `Java 采用抢占式的线程调度算法`,因此可能会出现某条线程常常获取到 CPU 控制权的情况,`为了让某些优先级比较低的线程也能获取到 CPU 控制权`,可以使用 `Thread.sleep(0)手动触发一次操作系统分配时间片的操作`,这也是`平衡 CPU 控制权的一种操作`。 #### 应用之限制 ##### sleep 实现 在没有利用 cpu 来计算时,不要让 while(true) 空转浪费 cpu,这时可以使用 yield 或 sleep 来让出 cpu 的使用权给其他程序 ```java while(true) { try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } } ``` - 可以用 wait 或 条件变量达到类似的效果 - 不同的是,后两种都需要加锁,并且需要相应的唤醒操作,一般适用于要进行同步的场景 - sleep 适用于无需锁同步的场景 ##### wait 实现 ```java synchronized(锁对象) { while(条件不满足) { try { 锁对象.wait(); } catch(InterruptedException e) { e.printStackTrace(); } } // do sth... } ``` ##### 条件变量实现 ```java lock.lock(); try { while(条件不满足) { try { 条件变量.await(); } catch (InterruptedException e) { e.printStackTrace(); } } // do sth... } finally { lock.unlock(); } ``` ### 四、join 方法详解 #### join使用示例 ```java @Slf4j(topic = "c.Test09") public class Test09 { static int r = 0; public static void main(String[] args) throws InterruptedException { test1(); } private static void test1() throws InterruptedException { log.debug("start"); Thread t1 = new Thread(() -> { log.debug("start"); sleep(1); log.debug("end"); r = 10; }); t1.start(); //t1.join(); log.debug("result:{}", r); log.debug("end"); } } ``` **运行结果** ``` 20:00:31.686 c.Test09 [main] - start 20:00:31.735 c.Test09 [Thread-0] - start 20:00:31.735 c.Test09 [main] - result:0 20:00:31.736 c.Test09 [main] - end 20:00:32.737 c.Test09 [Thread-0] - end ``` **结果分析** - 因为主线程和线程 t1 是并行执行的,t1 线程需要 1 秒之后才能算出 r=10 - 而主线程一开始就要打印 r 的结果,所以只能打印出 r=0 **解决方法** 在`t1.start()`之后增加如下代码 ``` t1.join(); ``` **运行结果** ``` 20:03:11.014 c.Test09 [main] - start 20:03:11.061 c.Test09 [Thread-0] - start 20:03:12.062 c.Test09 [Thread-0] - end 20:03:12.062 c.Test09 [main] - result:10 20:03:12.063 c.Test09 [main] - end ``` #### 应用之同步 以调用方角度来讲,如果 - 需要等待结果返回,才能继续运行就是同步 - 不需要等待结果返回,就能继续运行就是异步 ![05.并发编程之线程常见方法01.png](https://lilinchao.com/usr/uploads/2022/10/333451017.png) ##### 等待多个结果 **示例** ```java import lombok.extern.slf4j.Slf4j; import static com.lilinchao.concurrent.utils.Sleeper.sleep; /** * Created by lilinchao * Date 2022/10/7 * Description 1.0 */ @Slf4j(topic = "c.Test10") public class Test10 { static int r1 = 0; static int r2 = 0; public static void main(String[] args) throws InterruptedException { test2(); } private static void test2() throws InterruptedException { 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); } } ``` **运行结果** ``` 20:11:48.166 c.Test10 [main] - r1: 10 r2: 20 cost: 2002 ``` **说明** - 第一个 join:等待 t1 时, t2 并没有停止, 而在运行 - 第二个 join:1s 后, 执行到此, t2 也运行了 1s, 因此也只需再等待 1s **如果t1.join()和t2.join()颠倒顺序呢?** 运行结果 ``` 20:15:08.682 c.Test10 [main] - r1: 10 r2: 20 cost: 2003 ``` ![05.并发编程之线程常见方法02.png](https://lilinchao.com/usr/uploads/2022/10/4223181870.png) #### 有时效的join 当线程执行时间没有超过join设定时间 ```java @Slf4j(topic = "c.Test11") public class Test11 { static int r1 = 0; static int r2 = 0; public static void main(String[] args) throws InterruptedException { test3(); } public static void test3() throws InterruptedException { Thread t1 = new Thread(() -> { sleep(1); r1 = 10; }); long start = System.currentTimeMillis(); t1.start(); // 线程执行结束会导致 join 结束 t1.join(1500); long end = System.currentTimeMillis(); log.debug("r1: {} r2: {} cost: {}", r1, r2, end - start); } } ``` **运行结果** ``` 20:19:02.310 c.Test11 [main] - r1: 10 r2: 0 cost: 1002 ``` 当执行时间超时 ```java @Slf4j(topic = "c.Test11") public class Test11 { static int r1 = 0; static int r2 = 0; public static void main(String[] args) throws InterruptedException { test3(); } public static void test3() throws InterruptedException { Thread t1 = new Thread(() -> { sleep(2); r1 = 10; }); long start = System.currentTimeMillis(); t1.start(); // 线程执行结束会导致 join 结束 t1.join(1500); long end = System.currentTimeMillis(); log.debug("r1: {} r2: {} cost: {}", r1, r2, end - start); } } ``` **运行结果** ``` 20:20:39.378 c.Test11 [main] - r1: 0 r2: 0 cost: 1502 ``` *附参考原文链接* *https://blog.csdn.net/u013494827/article/details/125998256*
非特殊说明,本博所有文章均为博主原创。
如若转载,请注明出处:https://lilinchao.com/archives/2461.html
评论已关闭