zoukankan      html  css  js  c++  java
  • java基础---->java多线程之Join(二)

      如果主线程想等待子线程执行完成之后再结束,就可以使用join方法了。它的使用是等待线程对象销毁。今天我们就通过实例来学习一下多线程中join方法的使用。草在结它的种子,风在摇它的叶子。我们站着,不说话,就十分美好。

    Join方法的简单实例

    一、Join方法的简单使用

    import java.util.concurrent.TimeUnit;
    
    public class MyThread implements Runnable {
    
        @Override
        public void run() {
            try {
                int secondValue = (int) (Math.random() * 1000);
                System.out.println(secondValue);
                TimeUnit.MILLISECONDS.sleep(secondValue);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

      测试的主体类如下:

    public class MyThreadTest {
        public static void main(String[] args) {
            try {
                Thread thread = new Thread(new MyThread());
                Thread thread2 = new Thread(new MyThread());
                thread.start();
                thread2.start();
                thread.join();
                thread2.join();
                System.out.println("子线程MyThread执行完,我再执行");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    一次的运行结果如下:

    621
    335
    子线程MyThread执行完,我再执行

      方法join的作用是使所属的线程对象x正常执行run()方法中的任务,而使当前线程Z进行无限期的阻塞,等待线程X销毁后再继续执行线程Z后面的代码。

    二、对于join方法的分析

      我们首先写一个简单的测试类,来体会一下join方法的用法以及效果。我们在主线程中开启一下myThread的线程,在myThread线程里面会睡眠2秒,然后打印当前线程的名称。

    package com.linux.huhx.thread;
    
    import java.util.concurrent.TimeUnit;
    
    /**
     * Created by huhx on 2017-05-24.
     */
    public class ThreadJoinTest2 {
        public static void main(String[] args) throws InterruptedException {
            MyThread myThread = new MyThread();
            myThread.start();
            System.out.println("thread name " + Thread.currentThread().getName());
        }
    
        static class MyThread extends Thread {
            boolean flag = true;
    
            @Override
            public void run() {
                try {
                    TimeUnit.SECONDS.sleep(2);
                    System.out.println("thread name " + Thread.currentThread().getName());
                    flag = false;
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

      此时运行的结果如下,主线程里面的打印会先在控制台显示。两秒之后,打印myThread里面的字符。

    thread name main
    thread name Thread-0

      我们修改代码,在main方法的myThread.start();方法后面加上myThread.join();控制台打印如下:

    thread name Thread-0
    thread name main

      了解了Thread的join方法的表现与效果之后,现在我们就这个join方法做一个理解与分析。以下是它的代码:

    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;
            }
        }
    }

      代码是比较简单的,由于我们的测试是myThread.join(),所以isAlive()方法与wait方法都是myThread类(其实也是类)调用的,不过他们运行在主线程中。也就是说while (isAlive()) 代码是判断myThread线程是否是活跃的,wait(0)方法虽说是myThread调用的,然而运行在main线程中,所以是主线程(current thread)等待其它的线程(这里面是myThread线程)在myThread类(for this object)调用notify或者notifyAll方法。

    Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object.

      那么现在问题来了,其它的线程(相对于main线程而言)是什么时候调用了notify或者notifyAll方法把主线程唤醒呢。下面我们修改上述的测试代码,把上述修改的myThread.join();代码为如下代码:

    synchronized (myThread) {
        while (myThread.flag) {
            System.out.println("before flag = " + myThread.flag);
            myThread.wait();
            System.out.println("after flag = " + myThread.flag);
        }
    }

      现在运行程序,会有如下的结果。其实上述的代码和myThread.join方法的代码功能差不多。

    before flag = true
    thread name Thread-0
    after flag = false
    thread name main

      当主线程的程序运行到myThread.wait()的时候,它阻塞等待其它的线程在myThread对象上调用notify方法。在主线程等待的期间,myThread线程执行完毕之后,会有一个在当前线程类(myThread)的notifyAll的动作。作为对比,我们的代码修改如下:

    Object object = new Object();
    synchronized (object) {
        while (myThread.flag) {
            System.out.println("before flag = " + myThread.flag);
            object.wait();
            System.out.println("after flag = " + myThread.flag);
        }
    }

      由于是我们生成的object在主线程中调用wait方法,所以是synchronized (object)。我们可以看到主线程不会被唤醒,object.wait方法后面的代码不会得到执行。

      上面synchronized里面为什么是myThread呢,因为在主线程中是myThread对象调用的wait方法。如果修改成其它的,例如new Object()或者Object.class,会报错如下:

    Exception in thread "main" java.lang.IllegalMonitorStateException
    before flag = true
        at java.lang.Object.wait(Native Method)
        at java.lang.Object.wait(Object.java:502)
        at com.linux.huhx.thread.ThreadJoinTest2.main(ThreadJoinTest2.java:15)

      测试过程中积累的代码:

    package com.linux.huhx.thread;
    
    import java.util.concurrent.TimeUnit;
    
    /**
     * Created by huhx on 2017-05-24.
     */
    public class ThreadJoinTest2 {
        public static void main(String[] args) throws InterruptedException {
            MyThread myThread = new MyThread();
            myThread.start();
            // join()
    //        myThread.join();
    //        while (myThread.flag) {
    //            synchronized(myThread) {
    //                Thread.currentThread().wait();
    //            }
    //            System.out.println(Thread.currentThread().getName());
    //        }
            synchronized (myThread) {
                while (myThread.flag) {
                    myThread.wait();
                }
            }
            myThread.joinTest();
            System.out.println("thread name " + Thread.currentThread().getName());
        }
    
        static class MyThread extends Thread {
            boolean flag = true;
    
            @Override
            public void run() {
                try {
                    TimeUnit.SECONDS.sleep(2);
                    System.out.println("thread name " + Thread.currentThread().getName());
                    flag = false;
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
    
            public synchronized void joinTest() {
                while (flag) {
                    try {
                        wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
    
        }
    }
    View Code

    友情链接

    对于myThread是类和线程之间的关系,还是有些疑惑。就问题的本质而言,对于线程还是不能理解的很好。

  • 相关阅读:
    Linux-Deepin下搭建云笔记
    MySQL-脏页的刷新机制
    网络编程-Netty-writeAndFlush方法原理分析 以及 close以后是否还能写入数据?
    MySQL-SQL调优-引擎选错索引或者不使用索引分析 和 字符串加索引的方式思考
    字体的一些属性
    css清除浮动大全,共8种方法
    WEB前端开发人员须知的常见浏览器兼容问题及解决技巧
    区别各种IE浏览器和火狐的css写法
    IE和火狐浏览器对css解析的不一致
    使用photowap插件
  • 原文地址:https://www.cnblogs.com/huhx/p/baseusejavathreadjoin.html
Copyright © 2011-2022 走看看