join方法的使用

join方法的使用一、join方法1.1jon方法的作用使所属的线程对象x正常执行run()方法中的任务,而使当前线程y无限期的阻塞,直到x线程销毁后再继续执行线程y后面的代码。join方法具有使线程排队运行的作用,有些类似同步的运行的效果。1.2join与synchronized的区别join在内部使用wait()方法进行等待,而synchronized关键字使用的是”对象监视器”原理作为同步。…

大家好,又见面了,我是你们的朋友全栈君。

一、join方法

1.1 jon方法的作用

使所属的线程对象x正常执行run()方法中的任务,而使当前线程y无限期的阻塞,直到x线程销毁后再继续执行线程y后面的代码。

join方法具有使线程排队运行的作用,有些类似同步的运行的效果。

1.2 join与synchronized的区别

join在内部使用wait()方法进行等待,而synchronized关键字使用的是”对象监视器”原理作为同步。

1.3 方法join与异常

在join过程中,如果当前线程对象被中断,则当前线程出现异常。比如join方法遇到interrupt(),可能会出现异常。

1.4 方法join(lang)的使用

lang是时间的参数
myThread类:

public class myThread extends Thread{
    @Override
    public void run() {
        try {
            System.out.println(Thread.currentThread().getName() + "开始时间:" + System.currentTimeMillis());
            Thread.sleep(50000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

测试代码:

public class test {
    public static void main(String[] args) {
        try {
            myThread myThread = new myThread();
            myThread.start();
            myThread.join(2000);
            System.out.println(Thread.currentThread().getName() + "结束时间:" + System.currentTimeMillis());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

结果:

Thread-0开始时间:1557799194421
main结束时间:1557799196422

将join(2000)改成slepp(2000)效果一样,但是sleep()与join()对同步的处理上有区别:

1.5 join(long)与sleep(long)的区别

  • 方法long是在内部使用wait()方法来实现的,所以join(long)具有释放锁的特点
    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;
            }
        }
    }

当执行到wait()方法后,当前线程的锁被释放,其他线程就可以调用此线程中的同步方法了。
而Thread.sleep(long)却不释放锁。

1.6 join()方法的特点

join()方法大部分时间里先抢到锁,然后快速释放锁。

二、类TheadLoacl的使用

1.1 ThreadLoca类的背景

让每个线程都有自己私有的共享变量,而不是所有的线程都拥有一个共享变量。
该类解决的是变量在不同线程之间的隔离性的问题,也就是不同线程拥有自己的值,不同线程的值是可以放入Threadlocal类中进行保存的。

问题:
用同一个ThreadLocal对象,给不同两个线程设置私有共享变量:

public class test {
    public static void main(String[] args) {
       ThreadLocal local = new ThreadLocal();
        System.out.println(local.get());
        local.set("你好");
        System.out.println(local.get());
    }
}

1.2 验证线程变量的隔离性

子线程:

public class myThread extends Thread{
    ThreadLocal local;
    public myThread(ThreadLocal local){
        this.local = local;
    }
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            local.set("次线程" + i);
            System.out.println(local.get());
        }
    }
}

主线程:

public class test {
    public static void main(String[] args) {
        ThreadLocal local = new ThreadLocal();
        myThread my = new myThread(local);
        my.start();
        for (int i = 0; i < 100; i++) {
            local.set("主线程" + i);
            System.out.println(local.get());
        }
    }
}

结果:

"C:\Program Files\Java\jdk1.8.0_181\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2018.2.4\lib\idea_rt.jar=53954:C:\Program Files\JetBrains\IntelliJ IDEA 2018.2.4\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_181\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\rt.jar;D:\untitled2\out\production\untitled2" backup.test
主线程0
主线程1
主线程2
主线程3
次线程0
次线程1
次线程2
主线程4
主线程5

三、类InheritableThreadLocal

3.1 作用

在创建子线程时,子线程会接收所有可继承的线程局部变量的初始值,以获得父线程所具有的值。通常,子线程的值与父线程的值是一致的;但是,通过重写这个类中的 childValue 方法,子线程的值可以作为父线程值的一个任意函数。

3.2 子线程拿到父线程的值

类线程A继承主线程:

public class threadA extends Thread{
InheritableThreadLocal in = new InheritableThreadLocal();
public threadA(InheritableThreadLocal a){
    this.in = a;
}
    @Override
    public void run() {
        System.out.println(in.get());
    }
}

测试类:

public class test {
    public static void main(String[] args) {
        try {
            InheritableThreadLocal a = new InheritableThreadLocal();
            a.set("给主线程设置的值");
            Thread.sleep(1000);
            threadA threada = new threadA(a);
            threada.start();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

结果:

给主线程设置的值

子线程拿到了父线程设置的值。

3.3 常用方法

  • protected T childValue(T parentValue)
    parentvalue是从父线程继承下来的值,可以重写该函数,对继承下来的数据进行再一步的处理。
  • protected T initialValue()
    返回此线程局部变量的当前线程的“初始值”。线程第一次使用 get() 方法访问变量时将调用此方法,但如果线程之前调用了 set(T) 方法,则不会对该线程再调用 initialValue 方法。通常,此方法对每个线程最多调用一次,但如果在调用 get() 后又调用了 remove(),则可能再次调用此方法。
    该实现返回 null;如果程序员希望线程局部变量具有 null 以外的值,则必须为 ThreadLocal 创建子类,并重写此方法。通常将使用匿名内部类完成此操作。

3.4 子线程对拿到的父线程的值进行处理

test类:

public class test {
    public static void main(String[] args) {
        try {
            InheritableThreadLocal a = new InheritableThreadLocal(){
                @Override
                protected Object childValue(Object parentValue) {
                    return parentValue + "子线程将得到的父线程的值处理了一下";
                }
            };
            a.set("给主线程设置的值");
            Thread.sleep(1000);
            threadA threada = new threadA(a);
            threada.start();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

结果:
给主线程设置的值子线程将得到的父线程的值处理了一下

3.4 注意事项

如果子线程在获取值的同时,主线程将InteritableThreadLocal中的值进行更改,那么子线程取到的值还是旧值。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/132261.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 地表最强app官网ios_地表最强app下载

    地表最强app官网ios_地表最强app下载1.全历史当你村里的二大爷,国外回来的Uncle刘想要和你交流交流历史时,没关系,查看这个App。从生命起源到现代文明,从东亚到北美洲,从政权到经济,从军事到民生,保证让你上知天文,下知地理,聊得你二大爷也很蒙圈。2.Canva朋友相聚怎么少的了拍照发朋友圈!Canva提供朋友圈拍照模板以及各种特效,可爱的,青春的,春节气氛的,统统都有。万一结个婚呢,还可以在上面做贺卡。3.美丽修行…

    2022年8月22日
    11
  • matlab函数之length函数「建议收藏」

    matlab函数之length函数「建议收藏」文章来源:http://blog.sina.com.cn/yadan422 在MATLAB中:size:获取数组的行数和列数length:数组长度(即行数或列数中的较大值)numel:元素总数。s=size(A),当只有一个输出参数时,返回一个行向量,该行向量的第一个元素时数组的行数,第二个元素是数组的列数。[r,c]=size(A),当有两个输出参数时,size函数将数组的行数返回…

    2022年6月12日
    41
  • Java框架介绍

    Java框架介绍Java框架介绍

    2022年4月22日
    39
  • 怎么保存退出 vim 编辑

    怎么保存退出 vim 编辑保存命令按ESC键跳到命令模式,然后::w保存文件但不退出vim:wfile将修改另外保存到file中,不退出vim:w!强制保存,不推出vim:wq保存文件并退出vim:wq!强制保存文件,并退出vimq:不保存文件,退出vim:q!不保存文件,强制退出vim:e!放弃所有修改,从上次保存文件开始再编辑本文来自ij2155的CSDN博客…

    2022年4月29日
    65
  • jvm之指令重排_java指令重排

    jvm之指令重排_java指令重排引言:在Java中看似顺序的代码在JVM中,可能会出现编译器或者CPU对这些操作指令进行了重新排序;在特定情况下,指令重排将会给我们的程序带来不确定的结果…..1.&nbsp;什么是指令重排?&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在计算机执行指令的顺序在经过程序编译器编译之后形成的指令序列,一般而言,这个指…

    2022年8月31日
    1
  • java如何判断对象为空_java对象如何判断是否为空

    java如何判断对象为空_java对象如何判断是否为空在实际书写代码的时候,经常会因为对象为空,而抛出空指针异常java.lang.NullPointerException。下面我们来看一下java中判断对象是否为空的方法:(推荐:java视频教程)首先来看一下工具StringUtils的判断方法:一种是org.apache.commons.lang3包下的;另一种是org.springframework.util包下的。这两种StringUtils…

    2022年6月22日
    37

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号