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