java基本教程之join方法详解 java多线程教程

yizhihongxing

Java中的join()方法是多线程编程常用的一个方法,它的作用是让调用该方法的线程等待被调用线程执行完毕后再继续执行。本文将详细讲解join()方法的使用和注意事项。

什么是join()方法

在介绍join()方法之前,我们先回忆一下多线程的基础。在Java中,当创建一个线程对象并调用start()方法后,线程对象就会进入就绪状态,等待CPU分配时间片段并执行。当然,在实际应用中,很多时候我们需要协调不同线程的执行顺序。比如,在执行某些任务时,我们需要先让某个线程执行完毕后再执行其他线程。这时,就需要使用join()方法来实现。

join()方法是Thread类中的一个方法,它有一个可选参数,表示等待的时间,单位是毫秒。当某个线程调用了其他线程的join()方法时,它会被阻塞并等待其他线程执行完毕后继续执行。如果指定了超时时间,则等待的最大时间就是这个超时时间。

下面是一个示例代码,演示join()方法的基本用法:

public class JoinDemo {

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            System.out.println("t1开始执行");
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("t1执行完毕");
        });

        Thread t2 = new Thread(() -> {
            System.out.println("t2开始执行");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("t2执行完毕");
        });

        t1.start();
        t1.join(); // t1执行完毕后才会执行t2
        t2.start();
    }
}

在上面的代码中,我们首先创建了两个线程t1和t2,并分别用lambda表达式实现了它们的run()方法。我们希望在执行t2时先等待t1执行完毕,因此我们在t1调用完start()方法后接着调用了join()方法,指定t1执行完毕后才会执行t2。这样,t2就会一直等待t1执行完毕,直到t1执行完毕后才会开始执行。

运行上面的代码,输出结果如下:

t1开始执行
t1执行完毕
t2开始执行
t2执行完毕

可以看到,在调用了t1.join()方法后,主线程会一直等待t1执行完毕后再执行后续代码,因此先输出了t1执行完毕的语句。只有当t1执行完毕后,t2才会开始执行。

join()方法的注意事项

虽然join()方法是实现多线程协作的常用方法,但也有些需要注意的事项。

  1. join()方法抛出InterruptedException

当主线程或其他线程调用某个线程的join()方法时,如果该线程被中断,join()方法会抛出InterruptedException异常。因此,我们在调用join()方法时需要捕获该异常。

  1. join()方法会释放锁

当线程调用其他线程的join()方法时,它会持有被调用线程的锁,等待被调用线程执行完毕后,被调用线程释放锁后才会开始继续执行。这意味着,在调用join()方法时需要注意对共享变量的访问,以避免出现死锁等问题。

下面是一个示例代码,展示了join()方法可能导致的死锁问题:

public class JoinDeadlockDemo {

    private static final Object lock1 = new Object();
    private static final Object lock2 = new Object();

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            synchronized (lock1) {
                System.out.println("t1持有lock1,等待lock2");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (lock2) {
                    System.out.println("t1持有lock1和lock2");
                }
            }
        });

        Thread t2 = new Thread(() -> {
            synchronized (lock2) {
                System.out.println("t2持有lock2,等待lock1");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (lock1) {
                    System.out.println("t2持有lock1和lock2");
                }
            }
        });

        t1.start();
        t2.start();

        // 下面这两行代码会导致死锁
        t1.join(); 
        t2.join();
    }
}

在上面的代码中,我们创建了两个线程t1和t2,并通过synchronized关键字使它们持有lock1和lock2两个对象的锁。我们在t1和t2中都加入了一段等待时间和输出语句,在输出语句之前,先释放lock2的锁,再获取lock1的锁,确保执行t1和t2时都会先获取lock1对象的锁。

在主线程启动t1和t2后,接着调用了t1.join()和t2.join()方法,让主线程等待t1和t2执行完毕后再继续执行。由于t1持有lock1的锁,等待t2释放lock2的锁;而t2持有lock2的锁,等待t1释放lock1的锁。这就造成了t1和t2相互等待的死锁现象。

运行上面的代码,可以看到程序一直处于等待状态,没有任何输出。

为避免出现死锁等问题,在使用join()方法时,我们需要注意对共享变量的访问,并根据实际情况采取不同的策略。比如,可以通过设置适当的超时时间来避免死锁问题,或在持有锁的代码块中尽快释放锁等。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:java基本教程之join方法详解 java多线程教程 - Python技术站

(0)
上一篇 2023年5月18日
下一篇 2023年5月18日

相关文章

  • Java Spring 事务回滚详解

    首先我们来了解一下什么是事务回滚。在数据库操作中,如果某个操作出现问题导致异常抛出,那么如果没有进行事务回滚,这个操作可能会造成不可预知的结果,并且可能会导致数据不一致,操作失败等问题。事务回滚是一种机制,可以在发生异常时取消对数据库的已进行的所有更改,以维护数据一致性。 在 Spring 中,事务回滚通常通过使用事务管理器(Transaction Mana…

    Java 2023年5月26日
    00
  • Java spring单点登录系统

    Java Spring 单点登录系统攻略 简介 Java Spring单点登录系统是基于Spring框架实现的一种用户认证方式,它允许一个用户在多个应用系统中使用同一个身份验证凭证(例如用户名和密码)进行登录认证,从而实现了多个应用系统中的用户身份认证问题。 系统架构 该系统由三个部分组成:认证中心、客户端和数据库 认证中心:负责接收客户端发送的登录请求,验…

    Java 2023年5月20日
    00
  • Java Apache Commons报错“ZipUnsupportedCompressionMethodException”的原因与解决方法

    “DuplicateActionException”是Java的Struts框架中的一个异常,通常由以下原因之一引起: Action重复:如果存在重复的Action,则可能会出现此异常。例如,可能会在配置文件中定义两个名称相同的Action。 以下是两个实例: 例1 如果存在重复的Action,则可以尝试更改Action名称以解决此问题。例如,在Struts…

    Java 2023年5月5日
    00
  • java基础入门之IO流

    Java基础入门之IO流 本文主要介绍Java IO流的基础知识,包括IO流的概述、IO流分类、IO流的读取和写入操作以及常用IO流示例。 IO流概述 Java IO(Input/Output)流是一种用于处理输入/输出的机制。它提供了一种操作任意数据源的方式,包括磁盘文件、网络连接等等。 Java IO流由四个抽象类组成: InputStream:字节输入…

    Java 2023年5月26日
    00
  • Java File类的常用方法总结

    如果你需要使用Java程序中的文件操作功能,那么File类就是你需要用的类。本文通过对Java File类的常用方法进行总结来给你提供一份完整的攻略。 File类的常用方法 下面我们对File类的常用方法进行调查总结。 创建File对象 我们可以使用下面的代码来创建File对象。 File file = new File("文件路径");…

    Java 2023年6月1日
    00
  • dbcp 连接池不合理的锁导致连接耗尽解决方案

    为了讲解“dbcp连接池不合理的锁导致连接耗尽解决方案”,先来了解一下dbcp连接池的概念。 什么是dbcp连接池 dbcp连接池是一种用来存储连接和回收数据库连接的技术。它可以提供相对较快的数据库连接和释放之间的响应速度,以及对大量客户端请求进行响应的能力。 DBCP连接池出现的问题 但是,DBCP连接池也存在着一些问题。其中最显著的问题可能是连接池过度使…

    Java 2023年6月15日
    00
  • Java 基础语法

    Java 基础语法 Java 是一种广泛使用的编程语言,本文将向您介绍 Java 的基础语法。 数据类型 Java 中的数据类型分为两类:基本数据类型和引用数据类型。 基本数据类型 数据类型 描述 byte 字节数据类型。在存储空间上占据 1 个字节。 short 短整型数据类型。在存储空间上占据 2 个字节。 int 整型数据类型。在存储空间上占据 4 个…

    Java 2023年5月19日
    00
  • Java的Struts框架中的主题模板和国际化设置

    Java的Struts框架中的主题模板和国际化设置提供了一套全局约束的方式来统一管理Web应用的界面样式和用户语言环境,本文将为您提供完整的攻略,包括如何设置和使用主题模板和国际化设置。 设置主题模板 在Struts框架中,使用主题模板可以方便地统一管理Web应用的界面样式,通过以下步骤可以设置主题模板: 1. 在struts.xml中进行配置 在strut…

    Java 2023年5月20日
    00
合作推广
合作推广
分享本页
返回顶部