Java并发05:Thread的基本方法(2)-join方法-线程插队
本章主要对Java中Thread类的基本方法进行学习。
1.序言
Thread类作为线程的基类,提供了一系列方法,主要有:
- Thread.sleep(long):强制线程睡眠一段时间。
- Thread.activeCount():获取当前程序中存活的线程数。
- thread.start():启动一个线程。
- Thread.currentThread():获取当前正在运行的线程。
- thread.getThreadGroup():获取线程所在线程组。
- thread.getName():获取线程的名字。
- thread.getPriority():获取线程的优先级。
- thread.setName(name):设置线程的名字。
- thread.setPriority(priority):设置线程的优先级。
- thread.isAlive():判断线程是否还存活着。
- thread.isDaemon():判断线程是否是守护线程。
- thread.setDaemon(true):将指定线程设置为守护线程。
- thread.join():在当前线程中加入指定线程,使得这个指定线程等待当前线程,并在当前线程结束前结束。
- thread.yield():使得当前线程退让出CPU资源,把CPU调度机会分配给同样线程优先级的线程。
- thread.interrupt():使得指定线程中断阻塞状态,并将阻塞标志位置为true。
- object.wai()、object.notify()、object.notifyAll():Object类提供的线程等待和线程唤醒方法。
为了便于阅读,将以上所有方法,放在5篇文章中进行学习。
本章主要学习绿色字体标记的方法,其他方法请参加其他章节。
2.join()方法的理解
先来看join()方法的定义与注释。
/** * Waits for this thread to die. * * <p> An invocation of this method behaves in exactly the same * way as the invocation * * <blockquote> * {@linkplain #join(long) join}{@code (0)} * </blockquote> * * @throws InterruptedException * if any thread has interrupted the current thread. The * <i>interrupted status</i> of the current thread is * cleared when this exception is thrown. */ public final void join() throws InterruptedException { join(0); }
join()方法的作用:Waits for this thread to die.即:等待这个线程结束。
举例说明:
- 程序中有两个线程:[线程A] = threadA、[线程B]=threadB
- 在[线程A]的run()方法中,调用了threadB.join()
- 则[线程A]会在此段代码出,暂停后续代码的调用,等待[线程B]执行结束。
- [线程B]执行结束之后,[线程A]才会继续执行后续的未完代码。
关于join()方法更形象的说法:线程插队。
join()方法常用来保证:确保能够完整的获取到插队线程的处理结果。
3.实例代码与结果
3.1.示例场景
- 程序中有两个线程1和2,线程1独立运行需要100毫秒,线程2独立运行需要200毫秒。
- 线程2会对共享变量config进行赋值。
- 线程1会读取共享变量config。
- 我们期望线程1能够读取到被线程2赋值之后的变量config。
3.2.不用join()
代码:
/** * <p>java线程基本方法:join</p> * * @author hanchao 2018/3/11 16:03 **/ public class ThreadJoinDemo { private static final Logger LOGGER = Logger.getLogger(ThreadJoinDemo.class); //线程间的共享资源 private static String config = "配置未被初始化."; /** * <p>join:让当前线程等待指定的线程结束</p> * * @author hanchao 2018/3/11 16:04 **/ public static void main(String[] args) throws InterruptedException { //不加join LOGGER.info("==========不使用t.join()方法=========="); new Thread(() -> { LOGGER.info("[线程1]开始运行..."); Thread otherThread = new Thread(() -> { LOGGER.info("[线程2]开始运行..."); try { Thread.sleep(200);//线程2运行200毫秒 config = "配置已被[线程2]初始化."; } catch (InterruptedException e) { e.printStackTrace(); } LOGGER.info("[线程2]运行结束"); }); //启动线程2 otherThread.start(); try { Thread.sleep(100);//线程1运行100毫秒 } catch (InterruptedException e) { e.printStackTrace(); } LOGGER.info("[线程1]获取的配置为:" + config); LOGGER.info("[线程1]运行结束"); }).start();//启动线程1 } }
结果:
2018-03-12 12:40:24 INFO ThreadJoinDemo:22 - ==========不使用t.join()方法========== 2018-03-12 12:40:24 INFO ThreadJoinDemo:24 - [线程1]开始运行... 2018-03-12 12:40:24 INFO ThreadJoinDemo:26 - [线程2]开始运行... 2018-03-12 12:40:24 INFO ThreadJoinDemo:42 - [线程1]获取的配置为:配置未被初始化. 2018-03-12 12:40:24 INFO ThreadJoinDemo:43 - [线程1]运行结束 2018-03-12 12:40:24 INFO ThreadJoinDemo:33 - [线程2]运行结束
分析:
- 线程1执行时间比线程2更短,所以导致:线程1执行完了,线程2还没来得及对配置config进行赋值。这不是我们想要的结果。
3.3.添加join()
代码:
/** * <p>java线程基本方法:join</p> * * @author hanchao 2018/3/11 16:03 **/ public class ThreadJoinDemo { private static final Logger LOGGER = Logger.getLogger(ThreadJoinDemo.class); //线程间的共享资源 private static String config = "配置未被初始化."; /** * <p>join:让当前线程等待指定的线程结束</p> * * @author hanchao 2018/3/11 16:04 **/ public static void main(String[] args) throws InterruptedException { //使用t.join()方法 Thread.sleep(1000);//等待线程1和线程2都有运行完 System.out.println(); LOGGER.info("==========使用t.join()方法=========="); new Thread(() -> { LOGGER.info("[线程11]开始运行..."); Thread otherThread = new Thread(() -> { LOGGER.info("[线程22]开始运行..."); try { Thread.sleep(200);//线程22运行200毫秒 config = "配置已被[线程22]初始化."; } catch (InterruptedException e) { e.printStackTrace(); } LOGGER.info("[线程22]运行结束"); }); otherThread.start();//启动线程22 try { //在线程11中,加入线程22-->需要等到线程22结束之后才能结束线程11 otherThread.join(); } catch (InterruptedException e) { e.printStackTrace(); } LOGGER.info("[线程11]等待[线程22]结束"); try { Thread.sleep(100);//线程11运行100毫秒 } catch (InterruptedException e) { e.printStackTrace(); } LOGGER.info("[线程1]获取的配置为:" + config); LOGGER.info("[线程11]运行结束"); }).start();//启动线程11 } }
结果:
2018-03-12 12:40:25 INFO ThreadJoinDemo:49 - ==========使用t.join()方法========== 2018-03-12 12:40:25 INFO ThreadJoinDemo:51 - [线程11]开始运行... 2018-03-12 12:40:25 INFO ThreadJoinDemo:53 - [线程22]开始运行... 2018-03-12 12:40:25 INFO ThreadJoinDemo:60 - [线程22]运行结束 2018-03-12 12:40:25 INFO ThreadJoinDemo:69 - [线程11]等待[线程22]结束 2018-03-12 12:40:25 INFO ThreadJoinDemo:75 - [线程1]获取的配置为:配置已被[线程22]初始化. 2018-03-12 12:40:25 INFO ThreadJoinDemo:76 - [线程11]运行结束
分析:
- 在线程1的执行过程中,线程2通过join()加入。
- 这时,线程1不会再继续执行后续代码,而是等待线程2执行结束。
- 当线程2执行结束后,线程1继续执行未执行完的代码。
- 通过join()方法,达到了预期效果。