前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >join方法的使用

join方法的使用

作者头像
全栈程序员站长
发布2022-06-29 11:13:24
5680
发布2022-06-29 11:13:24
举报
文章被收录于专栏:全栈程序员必看

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

文章目录

一、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类:

代码语言:javascript
复制
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();
        }
    }
}

测试代码:

代码语言:javascript
复制
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();
        }
    }
}

结果:

代码语言:javascript
复制
Thread-0开始时间:1557799194421
main结束时间:1557799196422

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

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

  • 方法long是在内部使用wait()方法来实现的,所以join(long)具有释放锁的特点 join方法源码:
代码语言:javascript
复制
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对象,给不同两个线程设置私有共享变量:

代码语言:javascript
复制
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 验证线程变量的隔离性

子线程:

代码语言:javascript
复制
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());
        }
    }
}

主线程:

代码语言:javascript
复制
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());
        }
    }
}

结果:

代码语言:javascript
复制
"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继承主线程:

代码语言:javascript
复制
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());
    }
}

测试类:

代码语言:javascript
复制
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();
        }
    }
}

结果:

代码语言:javascript
复制
给主线程设置的值

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

3.3 常用方法

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

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

test类:

代码语言:javascript
复制
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.cn/132261.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 文章目录
  • 一、join方法
    • 1.1 jon方法的作用
      • 1.2 join与synchronized的区别
        • 1.3 方法join与异常
          • 1.4 方法join(lang)的使用
            • 1.5 join(long)与sleep(long)的区别
              • 1.6 join()方法的特点
              • 二、类TheadLoacl的使用
                • 1.1 ThreadLoca类的背景
                  • 1.2 验证线程变量的隔离性
                  • 三、类InheritableThreadLocal
                    • 3.1 作用
                      • 3.2 子线程拿到父线程的值
                        • 3.3 常用方法
                          • 3.4 子线程对拿到的父线程的值进行处理
                            • 3.4 注意事项
                            领券
                            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档