方法join的使用:
方法join()的作用是等待线程对象销毁;
public class MyThread extends Thread{
public void run() {
try {
int secondValue = (int)(Math.random() * 10000);
System.out.println(secondValue);
Thread.sleep(secondValue);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public class Test {
public static void main(String[] args) {
MyThread threadTest = new MyThread();
threadTest.start();
try {
threadTest.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("当ThreadTest执行完毕后再执行");
}
}
方法join具有使线程排队运行的作用,有些类似同步的运行效果。
join与synchronized的区别是:join在内部使用wait()方法进行等待,而sychronized关键字使用的是“对象监视器”原理作为同步;
在join过程中,如果当前线程对象被中断,则当前线程出现异常;
方法join(long)的使用:参数是设定等待的时间;
public class MyThread extends Thread{
public void run() {
try {
System.out.println("begin Timer = " + System.currentTimeMillis());
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//sleep方法不释放锁,join方法释放锁
//在这里都是两秒暂停,没有区别
public class Test {
public static void main(String[] args) {
MyThread t = new MyThread();
t.start();
try {
t.join(2000);
Thread.sleep(2000);
System.out.println(" end timer = " + System.currentTimeMillis());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
方法join()后面的代码提前运行:解释意外
public class ThreadB extends Thread{
synchronized public void run() {
try {
System.out.println("begin B ThreadName = "
+ Thread.currentThread().getName() + " "
+ System.currentTimeMillis());
Thread.sleep(5000);
System.out.println(" end B ThreadName = "
+ Thread.currentThread().getName() + " "
+ System.currentTimeMillis());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public class ThreadA extends Thread{
private ThreadB tb;
public ThreadA(ThreadB tb) {
super();
this.tb = tb;
}
public void run() {
try {
synchronized(tb) {
System.out.println("begin A ThreadName = "
+ Thread.currentThread().getName() + " "
+ System.currentTimeMillis());
Thread.sleep(5000);
System.out.println(" end A ThreadName = "
+ Thread.currentThread().getName() + " "
+ System.currentTimeMillis());
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public class RunFirst {
public static void main(String[] args) {
ThreadB tb = new ThreadB();
ThreadA ta = new ThreadA(tb);
ta.start();
tb.start();
System.out.println(" main end = " + System.currentTimeMillis());
}
}
public class RunAB {
public static void main(String[] args) {
try {
ThreadB tb = new ThreadB();
ThreadA ta = new ThreadA(tb);
ta.start();
tb.start();
tb.join(2000);
System.out.println(" main end "
+ System.currentTimeMillis());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
结论:方法join(2000)大部分是先运行的,也就是先抢到ThreadB的锁,然后快速进行释放;
类ThreadLocal的使用:
类ThreadLocal主要解决的就是每个线程绑定自己的值,可以将ThreadLocal类比喻成全局存放数据的盒子,盒子中可以存储每个线程的私有数据;
方法get()与null;验证线程变量的隔离性;
public class RunTL1 {
public static ThreadLocal tl = new ThreadLocal();
public static void main(String[] args) {
if (tl.get() == null) {
System.out.println("从未放过值");
tl.set("我的值");
}
System.out.println(tl.get());
System.out.println(tl.get());
}
}
public class Tools {
public static ThreadLocalExt tl = new ThreadLocalExt();
}
import java.util.Date;
public class ThreadLocalExt extends ThreadLocal{
protected Object initalValue() {
return new Date().getTime();
}
}
public class ThreadA extends Thread{
public void run() {
try {
for (int i = 0; i < 10; i++) {
System.out.println("在ThreadA线程中取得值 = " + Tools.tl.get() );
Thread.sleep(100);
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public class RunA {
public static void main(String[] args) {
try {
for (int i = 0; i < 10; i++) {
System.out.println(" 在main线程中取值 = " + Tools.tl.get());
Thread.sleep(100);
}
Thread.sleep(5000);
ThreadA ta = new ThreadA();
ta.start();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
类InheritableThreadLocal的使用:
值继承:
import java.util.Date;
public class InheritableThreadLocalExt extends InheritableThreadLocal{
protected Object initialValue() {
return new Date().getTime();
}
}
import com.highgo.tA1_ThreadLocal.Tools;
public class ThreadA extends Thread{
public void run() {
try {
for(int i = 0; i < 10; i++) {
System.out.println("在ThreadA线程中取值 = " + Tools.tl.get());
Thread.sleep(100);
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
import com.highgo.tA1_ThreadLocal.Tools;
//值继承
public class Run {
public static void main(String[] args) {
try {
for(int i = 0; i < 10; i++) {
System.out.println(" 在main线程中取值 = " + Tools.tl.get());
Thread.sleep(100);
}
Thread.sleep(5000);
ThreadA ta = new ThreadA();
ta.start();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
值继承再修改:
import java.util.Date;
public class InheritableThreadLocalExt extends InheritableThreadLocal{
protected Object initialValue() {
return new Date().getTime();
}
protected Object childValue(Object parentValue) {
return parentValue + " 我在子线程加的~";
}
}
import com.highgo.tA1_ThreadLocal.Tools;
public class ThreadA extends Thread{
public void run() {
try {
for(int i = 0; i < 10; i++) {
System.out.println("在ThreadA线程中取值 = " + Tools.tl.get());
Thread.sleep(100);
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
import com.highgo.tA1_ThreadLocal.Tools;
//值继承再修改
public class Run {
public static void main(String[] args) {
try {
for(int i = 0; i < 10; i++) {
System.out.println(" 在main线程中取值 = " + Tools.tl.get());
Thread.sleep(100);
}
Thread.sleep(5000);
ThreadA ta = new ThreadA();
ta.start();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
注意:如果子线程在取得值的同事,主线程将InheritableThreadLocal中的值进行更改,那么子线程取得的值还是旧值。