Android小知识-Java多线程相关(线程间通信)下篇

本平台的文章更新会有延迟,大家可以关注微信公众号-顾林海,如果大家想获取最新教程,请关注微信公众号,谢谢!

在一种场景中,比如main线程创建并启动了子线程,子线程需要做耗时操作,如果main线程想等子线程执行完成之后再结束,由于main线程比子线程先执行完,因此main线程获取不到子线程的值。我们看下面这段代码:

public class BeanThread extends Thread{

    @Override
    public void run() {
        super.run();

        try {
            System.out.println("执行一些耗时操作");
            Thread.sleep(3000);
            System.out.println("经过3秒执行完");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
复制代码

Client:

public class Client {

    public static void main(String[] args) {
        BeanThread thread=new BeanThread();
        thread.start();
        System.out.println("main线程执行完");
    }

}
复制代码

执行结果:

main线程执行完
执行一些耗时操作
经过3秒执行完
复制代码

那如何使主线程等子线程执行完并获取子线程的相关数据?可以使用join()方法,它的作用是使所属的线程对象正常执行run方法中的任务,而使当前线程进行无限期的阻塞,等待所属线程销毁后再继续执行当前线程后面的代码。比如:

public class Client {

    public static void main(String[] args) {
        BeanThread thread=new BeanThread();
        thread.start();
        try {
            thread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("main线程执行完");
    }

}
复制代码

再次执行,结果:

执行一些耗时操作
经过3秒执行完
main线程执行完
复制代码

可以发现执行join()方法后,使当前main线程阻塞,等待BeanThread线程执行结束后,再执行后面打印语句。

方法join具有使线程排队运行的作用,有些类似同步的运行效果。join与synchronized的区别是:join在内部使用wait()方法进行等待,具有释放锁的特点,而synchronized关键字使用的“对象监视器”原理作为同步。在join过程中,如果当前线程对象被中断,则当前线程出现异常。除了无参join方法外,还有一个有参方法join(long),传入的参数代表设定等待的时间。

变量值的共享可以使用public static变量的形式,所有的线程都使用同一个public static变量。如果想实现每一个线程都有自己的共享变量,可以使用ThreadLocal来实现,ThreadLocal主要解决的就是每个线程绑定自己的值。可以通过get()方法返回每个线程自己的值,默认返回的是null,可以通过继承ThreadLocal实现initialVaule()方法来设置默认值。

public class DefaultThreadLocal extends ThreadLocal {
    @Override
    protected Object initialValue() {
        return "默认值";
    }
}
复制代码

第一个线程:

public class ThreadFirst extends Thread {

    @Override
    public void run() {
        super.run();
        try {
            for(int i=0;i<5;i++){
                Client.DEFAULT_THREAD_LOCAL.set("第一个线程存入="+i);
                Thread.sleep(1000);
                System.out.println("第一个线程取出的值:"+Client.DEFAULT_THREAD_LOCAL.get());
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
复制代码

第二个线程:

public class ThreadSecond extends Thread {

    @Override
    public void run() {
        super.run();
        try {
            for(int i=0;i<5;i++){
                Client.DEFAULT_THREAD_LOCAL.set("第二个线程存入="+i);
                Thread.sleep(500);
                System.out.println("第二个线程取出的值:"+Client.DEFAULT_THREAD_LOCAL.get());
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
复制代码

Client:

public class Client {

    public static DefaultThreadLocal DEFAULT_THREAD_LOCAL=new DefaultThreadLocal();

    public static void main(String[] args) {
       ThreadFirst threadFirst=new ThreadFirst();
       ThreadSecond threadSecond=new ThreadSecond();
       threadFirst.start();
       threadSecond.start();
    }

}
复制代码

打印:

第二个线程取出的值:第二个线程存入=0
第二个线程取出的值:第二个线程存入=1
第一个线程取出的值:第一个线程存入=0
第二个线程取出的值:第二个线程存入=2
第二个线程取出的值:第二个线程存入=3
第一个线程取出的值:第一个线程存入=1
第二个线程取出的值:第二个线程存入=4
第一个线程取出的值:第一个线程存入=2
第一个线程取出的值:第一个线程存入=3
第一个线程取出的值:第一个线程存入=4
复制代码

通过打印结果,可以看出两个线程存入的变量具有隔离性,不会互相干扰,两个线程都往Client.DEFAULT_THREAD_LOCAL存入值,但每个线程还是能取出属于自己的数据。


838794-506ddad529df4cd4.webp.jpg

猜你喜欢

转载自juejin.im/post/5c0e5821f265da613d7be7b3