java 线程方法join的简单总结

虽然关于讨论线程join方法的博客已经很多了,不过个人感觉挺多都讨论得不够全面,所以我觉得有必要对其进行一个全面的总结。

  一、作用

  Thread类中的join方法的主要作用就是同步,它可以使得线程之间的并行执行变为串行执行。具体看代码:

  

public class JoinTest {
    public static void main(String [] args) throws InterruptedException {
        ThreadJoinTest t1 = new ThreadJoinTest("小明");
        ThreadJoinTest t2 = new ThreadJoinTest("小东");
        t1.start();
        /**join的意思是使得放弃当前线程的执行,并返回对应的线程,例如下面代码的意思就是:
         程序在main线程中调用t1线程的join方法,则main线程放弃cpu控制权,并返回t1线程继续执行直到线程t1执行完毕
         所以结果是t1线程执行完后,才到主线程执行,相当于在main线程中同步t1线程,t1执行完了,main线程才有执行的机会
         */
        t1.join();
        t2.start();
    }

}
class ThreadJoinTest extends Thread{
    public ThreadJoinTest(String name){
        super(name);
    }
    @Override
    public void run(){
        for(int i=0;i<1000;i++){
            System.out.println(this.getName() + ":" + i);
        }
    }
}

上面程序结果是先打印完小明线程,在打印小东线程;  

上面注释也大概说明了join方法的作用:在A线程中调用了B线程的join()方法时,表示只有当B线程执行完毕时,A线程才能继续执行。注意,这里调用的join方法是没有传参的,join方法其实也可以传递一个参数给它的,具体看下面的简单例子:

public class JoinTest {
    public static void main(String [] args) throws InterruptedException {
        ThreadJoinTest t1 = new ThreadJoinTest("小明");
        ThreadJoinTest t2 = new ThreadJoinTest("小东");
        t1.start();
        /**join方法可以传递参数,join(10)表示main线程会等待t1线程10毫秒,10毫秒过去后,
         * main线程和t1线程之间执行顺序由串行执行变为普通的并行执行
         */
        t1.join(10);
        t2.start();
    }

}
class ThreadJoinTest extends Thread{
    public ThreadJoinTest(String name){
        super(name);
    }
    @Override
    public void run(){
        for(int i=0;i<1000;i++){
            System.out.println(this.getName() + ":" + i);
        }
    }
}

上面代码结果是:程序执行前面10毫秒内打印的都是小明线程,10毫秒后,小明和小东程序交替打印。

所以,join方法中如果传入参数,则表示这样的意思:如果A线程中掉用B线程的join(10),则表示A线程会等待B线程执行10毫秒,10毫秒过后,A、B线程并行执行。需要注意的是,jdk规定,join(0)的意思不是A线程等待B线程0秒,而是A线程等待B线程无限时间,直到B线程执行完毕,即join(0)等价于join()。

  

  二、join与start调用顺序问题

  上面的讨论大概知道了join的作用了,那么,入股 join在start前调用,会出现什么后果呢?先看下面的测试结果

public class JoinTest {
    public static void main(String [] args) throws InterruptedException {
        ThreadJoinTest t1 = new ThreadJoinTest("小明");
        ThreadJoinTest t2 = new ThreadJoinTest("小东");
        /**join方法可以在start方法前调用时,并不能起到同步的作用
         */
        t1.join();
        t1.start();
        //Thread.yield();
        t2.start();
    }

}
class ThreadJoinTest extends Thread{
    public ThreadJoinTest(String name){
        super(name);
    }
    @Override
    public void run(){
        for(int i=0;i<1000;i++){
            System.out.println(this.getName() + ":" + i);
        }
    }
}

上面代码执行结果是:小明和小东线程交替打印。

所以得到以下结论:join方法必须在线程start方法调用之后调用才有意义。这个也很容易理解:如果一个线程都没有start,那它也就无法同步了。

  三、join方法实现原理

  有了上面的例子,我们大概知道join方法的作用了,那么,join方法实现的原理是什么呢?

  其实,join方法是通过调用线程的wait方法来达到同步的目的的。例如,A线程中调用了B线程的join方法,则相当于A线程调用了B线程的wait方法,在调用了B线程的wait方法后,A线程就会进入阻塞状态,具体看下面的源码:

public final synchronized void join(long millis)
    throws InterruptedException {
        long base = System.currentTimeMillis();
        long now = 0;

        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (millis == 0) {
            while (isAlive()) {
                wait(0);
            }
        } else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }

从源码中可以看到:join方法的原理就是调用相应线程的wait方法进行等待操作的,例如A线程中调用了B线程的join方法,则相当于在A线程中调用了B线程的wait方法,当B线程执行完(或者到达等待时间),B线程会自动调用自身的notifyAll方法唤醒A线程,从而达到同步的目的。

  

时间: 2024-08-09 03:12:49

java 线程方法join的简单总结的相关文章

java 线程方法join

public class JoinTest { public static void main(String [] args) throws InterruptedException { ThreadJoinTest t1 = new ThreadJoinTest("小明"); ThreadJoinTest t2 = new ThreadJoinTest("小东"); t1.start(); /**join的意思是使得放弃当前线程的执行,并返回对应的线程,例如下面代

java线程sleep(),join()和yield方法

join()方法示例如下: 1 public class Thread1{ 2 public static void main(String[] args) { 3 TestThread t=new TestThread("t"); 4 t.start(); 5 try{ 6 t.join(); //类似于调用run()方法. 7 }catch (InterruptedException e) { 8 9 } 10 for (int i=0;i<=10 ;i++ ) { 11 S

Java线程--interrupt join yield setDaemon常用方法的使用

概念: 操作系统可以有多个进程,一个线程可以有一个或多个线程.进程与进程之间不共享内存,都在各自的空间中运行.而线程不仅可以共享内存,还可以用有一个自己的内存空间,叫做线程栈. 线程又称轻量级进程.Java的线程是靠CPU时间片的快速切换实现的,并不是真正的同时进行.每个线程有独立的线程栈和程序计数器.线程在自己的栈中存储变量,使数据互不干扰,对于共同资源,容易引发并发问题,需要同步处理. 创建线程常用的两种方式: 1.继承Thread类,重写run() 2.实现Runnable接口 线程生命周

java 线程协作 join()

在实际开发中我们往往会遇到这样的情况一个线程的执行需要依赖另一个线程执行后的结果.即主线程生成并起动了子线程,如果子线程里要进行大量的耗时的运算,主线程往往将于子线程之前结束,但是如果主线程处理完其他的事务后,需要用到子线程的处理结果,也就是主线程需要等待子线程执行完成之后再结束,这个时候就要用到join()方法了. join() join() 方法主要是让调用该方法的thread完成run方法里面的任务后, 再执行join()方法后面的代. 主线程生成并起动了子线程,而子线程里要进行大量的耗时

java 线程池socket实现简单http服务器

---恢复内容开始--- 要点: 1.只需回应Get请求,将本地的lena.jpg返回给客户端 2.使用最基本的socket编程 3.使用线程池进行线程管理 4.将lena.jpg读入内存中,减少IO次数 5.MyHttpServer作为服务器类,ServerThread作为服务处理线程类 1.加入线程池 ExecutorService pool = Executors.newFixedThreadPool(MaxClientNums); 2.有客户访问则开启服务线程并将其加入线程池 while

java 线程 wait join sleep yield notify notifyall synchronized

韩梦飞沙  韩亚飞  [email protected]  yue31313  han_meng_fei_sha 休息方法 : 在指定时间内 让该线程 暂停, 不会释放 锁标志. 等待方法: 让 该 线程等待, 如果 有锁标志, 将会释放 锁标志. 唤醒当前对象锁的等待线程 用 通知 或者 通知所有 方法,  等待方法 和 通知 方法 必须在 同步 函数 或 同步 块 中 进行调用. yield 方法 yield 是  n. 产量:收益  vt. 屈服:出产,产生:放弃 的意思. 加入 方法  

java线程使用示例——最简单的线程

线程使用示例一: public class ThreadTest { public static void main(String[] args) { //线程使用示例一: new Thread() { public void run() { while (true) { try { System.out.println("线程输出"); //休眠两秒 Thread.sleep(2 * 1000); } catch (InterruptedException e) { e.printS

Java 工厂方法模式的简单示例

工厂方法模式:也叫工厂模式,属于类创建型模式,工厂父类(接口)负责定义产品对象的公共接口,而子类工厂则负责创建具体的产品对象. 目的:是为了把产品的实例化操作延迟到子类工厂中完成,通过工厂子类来决定究竟应该实例化哪一个产品具体对象. 工厂方法模式包含四个部分: 1.抽象产品:产品对象同一的基类,或者是同一的接口. 2.具体的产品:各个不同的实例对象类 3.抽象工厂:所有的子类工厂类的基类,或是同一的接口 4.具体的工厂子类:负责每个不同的产品对象的实际创建 具体代码示例,我们以水果作为演示. 定

Java线程join示例详解

Java线程的join方法可用于暂停当前线程的执行直至目标线程死亡.Thread中一共有三个join的重载方法. public final void join():该方法将当前线程放入等待队列中,直至被它调用的线程死亡为止.如果该线程被中断,则会抛出InterruptedException异常. public final synchronized void join(long millis):该方法用于让当前线程进入等待状态,直至被它调用的线程死亡或是经过millis毫秒.由于线程的执行依赖于操