并发编程专题(四)-线程的控制

网友投稿 991 2022-11-22

并发编程专题(四)-线程的控制

并发编程专题(四)-线程的控制

1.Join方法

Thread提供了让一个线程等待另一个线程完成的方法join()方法。当在某个程序执行流中调用其他线程的join()方法时,调用线程将被阻塞,直到被join()方法加入的join线程执行完为止。join()方法通常由使用线程的程序调用,以将大问题划分成许多小问题,每个小问题分配一个线程。当所有的小问题都得到处理后,再调用主线程来进一步操作。例如当在主线程当中执行到t1.join()方法时,就认为主线程应该把执行权让给t1。

代码演示:

/** * @author bruceliu * @create 2019-06-01 23:12 * @description 当在主线程当中执行到t1.join()方法时,就认为主线程应该把执行权让给t1 */public class JoinThread extends Thread{ // 提供一个有参数的构造器,用于设置该线程的名字 public JoinThread(String name) { super(name); } // 重写run方法,定义线程执行体 public void run() { for (int i = 0; i < 100; i++) { System.out.println(getName() + "" + i); } } public static void main(String[] args) throws Exception { // 启动子线程 new JoinThread("新线程------>").start(); for (int i = 0; i < 100; i++) { if (i == 20) { JoinThread jt = new JoinThread("被Join的线程"); jt.start(); // main线程调用了jt线程的join()方法,main线程 // 必须等jt执行结束才会向下执行 jt.join(); } System.out.println(Thread.currentThread().getName() + "======>" + i); } }}

结果分析: 上面程序中一共有3个线程,主方法开始时就启动了名为"新线程"的子线程,该子线程将会和main线程并发执行。当主线程的循环变量i等于20时启动了名为"被Join的线程"的线程,该线程不会和main线程并发执行。main线程必须等该线程执行结束后才可以向下执行。在名为"被Join的线程"的线程执行时,实际上只有2个子线程并发执行,而主线程处于等待状态。运行上面程序。从上面的运行结果可以看出,主线程执行到i=20时启动,并join了名为"被Join的线程"的线程,所以主线程将一直处于阻塞状态,直到名为"被Join的线程"的线程执行完成。

2. 线程优先级

在任意时刻,当有多个线程处于可运行状态时,运行系统总是挑选一个优先级最高的线程执行,只有当线程停止、退出或者由于某些原因不执行的时候,低优先级的线程才可能被执行两个优先级相同的线程同时等待执行时,那么运行系统会以round-robin的方式选择一个线程执行(即轮询调度,以该算法所定的)(Java的优先级策略是抢占式调度!)被选中的线程可因为一下原因退出,而给其他线程执行的机会:1) 一个更高优先级的线程处于可运行状态(Runnable)2)线程主动退出(yield),或它的run方法结束3)在支持分时方式的系统上,分配给该线程的时间片结束Java运行系统的线程调度算法是抢占式(preemptive)的,当更高优先级的线程出现并处于Runnable状态时,运行系统将选择高优先级的线程执行例外地,当高优先级的线程处于阻塞状态且CPU处于空闲时,低优先级的线程也会被调度执行

Java线程的优先级是一个整数,其取值范围是1 (Thread.MIN_PRIORITY ) - 10 (Thread.MAX_PRIORITY )。 Thread源代码里对NORM_PRIORITY (数值为5) 的注释是“线程默认的优先级”

public static final int MIN_PRIORITY = 1; public static final int NORM_PRIORITY = 5; public static final int MAX_PRIORITY = 10;

代码示例:

package com.bruceliu.demo10;/*** @author bruceliu* @create 2019-06-01 23:29* @description 线程的优先级*/public class PriorityExample{ public static void main(String[] args){ Thread a = new PThread("A"); Thread b = new PThread("B"); // 注意设置了优先级, 不代表每次都一定会被执行。 只是CPU调度会有限分配 a.setPriority(10); //设置优先级 a.setPriority(1); b.start(); a.start(); }}class PThread extends Thread{ public PThread(String n){ super(n); } public void run(){ for(int i=0; i<10; i++){ if(i%2 == 0){ System.out.print(getName()); } } }}

3. 线程睡眠-sleep方法

如果需要让当前正在执行的线程暂停一段时,并进入阻塞状态,则可以通过调用Thread类的静态sleep()方法来实现。当前线程调用sleep()方法进入阻塞状态后,在其睡眠时间段内,该线程不会获得执行的机会,即使系统中没有其他可执行的线程,处于sleep()中的线程也不会执行,因此sleep()方法常用来暂停程序的执行。

下面程序调用sleep()方法来暂停主线程的执行,因为该程序只有一个主线程,当主线程进入睡眠后,系统没有可执行的线程,所以可以看到程序在sleep()方法处暂停.示例代码:

/** * @author bruceliu * @create 2019-06-01 23:36 * @description sleep方法 */public class SleepTest { public static void main(String[] args) throws Exception { for (int i = 0; i < 10; i++) { System.out.println("当前时间: " + new Date()); // 调用sleep方法让当前线程暂停1s。 Thread.sleep(1000); } }}

上面程序中sleep()方法将当前执行的线程暂停1秒,运行上面程序,看到程序依次输出10条字符串,输出2条字符串之间的时间间隔为1秒.

4. 线程让步-yield方法

yield()方法是一个和sleep()方法有点相似的方法,它也是Threard类提供的一个静态方法,它也可以让当前正在执行的线程暂停,但它不会阻塞该线程,它只是将该线程转入就绪状态。yield()只是让当前线程暂停一下,让系统的线程调度器重新调度一次,完全可能的情况是:当某个线程调用了yield()方法暂停之后,线程调度器又将其调度出来重新执行。

实际上,当某个线程调用了yield()方法暂停之后,只有优先级与当前线程相同,或者优先级比当前线程更高的处于就绪状态的线程才会获得执行的机会。下面程序使用yield()方法来让当前正在执行的线程暂停。

yield()让当前正在运行的线程回到可运行状态,以允许具有相同优先级的其他线程获得运行的机会。因此,使用yield()的目的是让具有相同优先级的线程之间能够适当的轮换执行。但是,实际中无法保证yield()达到让步的目的,因为,让步的线程可能被线程调度程序再次选中。

代码示例:

package com.bruceliu.demo12;/** * @author bruceliu * @create 2019-06-01 23:42 * @description 线程让步---yield() */public class YieldTest extends Thread { public YieldTest(String name) { super(name); } // 定义run方法作为线程执行体 public void run() { for (int i = 0; i < 50; i++) { System.out.println(getName() + "" + i); // 当i等于20时,使用yield方法让当前线程让步 if (i == 20) { Thread.yield(); } } } public static void main(String[] args) throws Exception { // 启动两条并发线程 YieldTest yt1 = new YieldTest("高级-------->"); // 将ty1线程设置成最高优先级 //yt1.setPriority(Thread.MAX_PRIORITY); yt1.start(); YieldTest yt2 = new YieldTest("低级"); // 将yt2线程设置成最低优先级 //yt2.setPriority(Thread.MIN_PRIORITY); yt2.start(); }}

5. yield方法和sleep方法对比

6. 面试题

有T1、T2、T3三个线程,你怎样保证T2在T1执行完后执行,T3在T2执行完后执行代码示例:

/** * @author bruceliu * @create 2019-06-01 23:52 * @description */public class JoinThreadDemo02 { public static void main(String[] args) { Thread t1 = new Thread(new Runnable() { public void run() { for (int i = 0; i < 20; i++) { System.out.println("t1,i:" + i); } } }); Thread t2 = new Thread(new Runnable() { public void run() { try { t1.join(); } catch (Exception e) { // TODO: handle exception } for (int i = 0; i < 20; i++) { System.out.println("t2,i:" + i); } } }); Thread t3 = new Thread(new Runnable() { public void run() { try { t2.join(); } catch (Exception e) { // TODO: handle exception } for (int i = 0; i < 20; i++) { System.out.println("t3,i:" + i); } } }); t1.start(); t2.start(); t3.start(); }}

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:springboot动态调用实现类方式
下一篇:Redis专题(十二)-Redis集群
相关文章

 发表评论

暂时没有评论,来抢沙发吧~