线程间通信


title: 对象及变量的并发访问
categories: Java多线程编程核心技术
tags: 多线程
time: 2019-04-23 22:18:02

方法join的使用

大多数情况下,主线程启动子线程,子线程需要执行比较耗时的操作,主线程会先于子线程执行结束,但是主线程需要等待获取到子线程的执行结果,那么就需要join方法了。

学习join前的铺垫

线程的执行顺序是无法控制的。

用join()来解决

用join可以解决上一个问题。
join具有让线程排队运行的效果,有些类似同步的效果。join与synchronized的区别:join内部使用wait方法进行等待,而synchronized使用"对象监视器"的原理作为同步。

public class Test{
	public static void main(String[] args) {
		sout("开始执行");
		MyThread th = new MyThread();
		th.start();
		th.join();
		sout("最后执行")
	}
}

方法join()和异常

在一个线程中,方法join()和interrupt()方法相遇,则会出现异常InterruptedException,不会影响到其他线程,

public class JoinTest {
    public static void main(String[] args) {
        try {
            ThreadA threadA = new ThreadA();
            threadA.start();
            threadA.interrupt();
            Thread.sleep(5000);
            System.out.println("Main 执行结束");
        } catch (InterruptedException e) {
            e.printStackTrace();
            System.out.println("抛出异常了");
        }
    }

}

class ThreadA extends Thread {

    @Override
    public void run() {
        try {
            super.run();
            System.out.println("ThreadA开始执行了");
            join();
            System.out.println("ThreadA执行结束");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

运行结果:

ThreadA开始执行了
java.lang.InterruptedException
	at java.lang.Object.wait(Native Method)
	at java.lang.Thread.join(Thread.java:1245)
	at java.lang.Thread.join(Thread.java:1319)
	at chapter4.ThreadA.run(JoinTest.java:26)
Main 执行结束

方法join(long)的使用

参数long表示等待的时间。

public class JoinTest {
    public static void main(String[] args) {
        try {
            ThreadA threadA = new ThreadA();
            threadA.start();
            Thread.sleep(5000);
            System.out.println("Main 执行结束");
        } catch (InterruptedException e) {
            e.printStackTrace();
            System.out.println("抛出异常了");
        }
    }

}

class ThreadA extends Thread {

    @Override
    public void run() {
        try {
            super.run();
            System.out.println("ThreadA开始执行了" + System.currentTimeMillis());
            join(5000);
            System.out.println("ThreadA执行结束" + System.currentTimeMillis());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

执行结果:

ThreadA开始执行了1556069846889
Main 执行结束
ThreadA执行结束1556069851892

方法join(long)和sleep(long)的区别

join(long)内部是使用wait(long)的方式来实现的,所有具有释放锁的特点;

源码:调用wait(long)方法后会释放当前线程的锁,那么其他线程可以调用此线程中的同步方法了。

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

sleep(long)方法执行后不释放锁。

join方法后面的代码提前运行:出现意外

TODO:暂存

类ThreadLocal的使用

变量值的共享可以使用public static变量的方式,所有线程都使用同一个public static的变量。
而ThreadLocal就是解决每个线程拥有自己单独的一个共享变量。

方法get()与null

public class ThreadLocalGetNull {

    private static ThreadLocal threadLocal = new ThreadLocal();

    public static void main(String[] args) {

        if (threadLocal.get() == null) {
            System.out.println("threadLocal没有值");
            threadLocal.set("设置的值");
        }
        System.out.println(threadLocal.get());
        System.out.println(threadLocal.get());
    }
}

运行结果:

threadLocal没有值
设置的值
设置的值

验证线程变量的隔离性

解决get()返回null的问题

继承ThreadLocal类,重写initialValue方法

import java.util.Date;

public class ThreadLocalExt extends ThreadLocal<Date> {
    @Override
    protected Date initialValue() {
        return new Date();
    }

    private static ThreadLocalExt threadLocalExt = new ThreadLocalExt();

    public static void main(String[] args) {
        System.out.println(threadLocalExt.get());
    }
}

运行结果:

Tue Apr 23 21:44:59 CST 2019

再次验证线程变量的隔离性

类InheritableThreadLocal的使用

值继承再修改

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值