1.首先我们来了解java中的一个join()方法,它是Thread中的一个方法,join()方法在java的API文档时的描述为:
join()方法 在主线程中,加入了myThread.join(); 把谁加入了就要等谁。同时join还有join(millis)方法,可以加入等待时间,效果上类似sleep,但是还是有实际区别的。join底层是wait方法,所以它是会释放对象锁的,而sleep在同步的方法中是不释放对象锁的,只有同步方法执行完毕,其他线程才可以执行。当main线程调用到Thread-0的时候,这个时候main线程是等待状态,直到join守护完毕才执行下面的东西。join方法是先将线程池中的其它线程wait状态,join执行完毕,又调用了notifyAll()唤醒所有线程中的线程。下面画个图简单模拟一下过程:
下面我们通过代码简单的测试一下join方法代码如下:
public class Domajoin {
public static void main(String[] args) {
Damo1 dom=new Damo1();
Thread t1=new Thread(dom);
t1.start();
for (int i = 0; i <50; i++) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(i==20){
try {
t1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("main="+i);
}
}
}
class Damo1 implements Runnable{
public void run() {
for (int i = 0; i <50; i++) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+i);
}
}
}
我们在mian这个线程加入Dom1a这个线程类的join方法,我们发现刚开始时两线程交替打印在mian这个线程的i打印到20时,便停止打印此时只有Doma1这个线程的i再继续打印,当它打印完以后mian中的i才开始继续打印。
2.我们来讲讲线程的中断。
我们知道线程一启动后就是不可控的,除非线程中断自身第一种方式,我们通过interrupt()方法来实现,interrupt只是起到一个中断标记的作用,然后我们通过Thread类里面的public static boolean interrupted()来测试这个线程是否中断,该方法可以清除线程的中断转态,该方法被连续调用两次第二个调用将返回false(除非当前线程再次中断,在第一个调用已经清除中断状态之后,在第二个调用之前已经检查过)下面我们通过代码测试怎么使用interrupt()中断标记来实现线程的中断:
public class Damointerrupt {
public static void main(String[] args) {
Damon1 dd=new Damon1();
Thread t1=new Thread(dd);
t1.start();
for (int i = 0; i < 50; i++) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("main="+i);
if(i==20){
t1.interrupt();//中断线程,只是一个中断标记
}
}
}
}
class Damon1 implements Runnable{
public void run() {
for (int i = 0; i <50; i++) {
if(Thread.interrupted()){//测试中断状态,并且会把中断状态清除
break;
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();//重新打回中断状态
}
System.out.println(Thread.currentThread().getName()+"="+i);
}
}
}
这样Damo线程会在i打印到20时中断:
2.我们发现这样的方法比较麻烦,我们在中断线程时一般采用中断线程的另外一种方式:自定义标记法:
代码如下:
public class Damoboolean {
public static void main(String[] args) {
Damo2 dd=new Damo2();
Thread t1=new Thread(dd);
t1.start();
for (int i = 0; i <50; i++) {
System.out.println("main="+i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(i==20){
dd.flag=false;//当布尔值改为false时线程中断
}
}
}
}
class Damo2 implements Runnable{
public boolean flag=true;
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
public void run() {
int i=0;
while(flag){
System.out.println(Thread.currentThread().getName()+"="+i++);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
我们发现这种自定义标记的方式很容易实现线程的中断,笔者推荐使用这种方法