天天看点

join方法和线程终止的三大方法

线程终止的方法

1、join(方法)

join()方法,其实是线程间通信的一种方法

如果在主线程中调用该方法,会让主线程休眠,

让调用该方法的线程执行完毕后再恢复执行主线程

从运行态到阻塞态 join(),会释放对象锁

阻塞态到就绪态 join()线程执行完毕

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

class MyThread implements Runnable{
    @Override
    public void run() {
        for(int i=0;i<3;i++){
            System.out.println(Thread.currentThread().getName()+"、"+i);
        }
    }
}

public class Test {
    public static void main(String[] args) {
        System.out.println("main线程开始");
        MyThread myThread=new MyThread();
        new Thread(myThread,"子线程A").start();
        System.out.println("main线程结束");

    }
    public static void PrintTime(){
        Date date=new Date();
        DateFormat dateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String str=dateFormat.format(date);
        System.out.println(str);
    }
}
           

运行结果:

join方法和线程终止的三大方法

在我们进行调用join()方法之前,我们发现,主线程,子线程,自己调用自己的线程

join方法只是对于object提供的wait()做了一层封装。

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

class MyThread implements Runnable{
    @Override
    public void run() {
        System.out.println("主线程休眠开始...." );
        Test.PrintTime();
        try {
        Thread.sleep(3000);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
        System.out.println("主线程休眠结束....");
        Test.PrintTime();
        }
    }


public class Test {
    public static void main(String[] args)throws InterruptedException {
        System.out.println("main线程开始");
        MyThread myThread=new MyThread();
       Thread thread= new Thread(myThread,"子线程A");
       thread.start();
       thread.join();
        thread.sleep(2000);
        System.out.println("main线程结束");

    }
    public static void PrintTime(){
        Date date=new Date();
        DateFormat dateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String str=dateFormat.format(date);
        System.out.println(str);
    }
}
           

运行结果:

join方法和线程终止的三大方法

我们可以发现,在执行join方法之后,我们的主线程开始停止运行,先执行我们的子线程。

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

这是实现join方法的一段源码,我们可以可以看到join()方法的本质只是一种对于wait方法的封装。

线程停止的方法

1、设置标志位停止线程

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

class MyThread implements Runnable{
    private boolean flag=true;
    @Override
    public void run() {
       int i=1;
       while(flag){
           System.out.println(Thread.currentThread().getName()+"第"+i+"次执行。。。");
           try{
               Thread.sleep(1000);
           }catch (InterruptedException e){
               e.printStackTrace();
           }
           i++;
       }
       }
    public void setFlag(boolean flag){
        this.flag=flag;
    }
    }


public class Test {
    public static void main(String[] args)throws InterruptedException {
        MyThread mt=new MyThread();
        Thread thread=new Thread(mt,"A");
        thread.start();
        thread.sleep(5000);
        mt.setFlag(false);
    }

}

           

运行结果:

join方法和线程终止的三大方法
  • 我们可以看到,我们通过设置标志位,我们可以清晰地看见在我们主线程等待5秒的时间里面,
  • 我们的子线程每次运行只等待1秒,所以的子线程在等待子线程的过程中,我们的子线程运行了5次。
  • 5秒之后,由于我们的在主线程中将子线程设置的标志位改变,所以我们的子线程退出。

**

2、调用stop方法

**

调用stop方法强制停止线程,该方法不安全,已经被Deprecated

这种停止方式很同意产生我们的废弃数据

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

class MyThread implements Runnable{
    private boolean flag=true;
    @Override
    public void run() {
        int i=1;
        while(flag){
            System.out.println(Thread.currentThread().getName()+"第"+i+"次执行。。。");
            try{
                Thread.sleep(1000);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
            i++;
        }
    }
}


public class Test {
    public static void main(String[] args)throws InterruptedException {
        MyThread mt=new MyThread();
        Thread thread=new Thread(mt,"A");
        thread.start();
        thread.sleep(5000);
        thread.stop();
    }

}
           

运行结果:

join方法和线程终止的三大方法

stop方法不安全在一旦调用它,它一旦执行,那我们调用它的线程会立马退出,那么很有可能产生垃圾数据。

3、调用Thread类的Interrupt()方法(能用不好理解)

interrupt()方法只是将线程状态置为中断状态而已,它不会中断一个正在运行的线程。此方法只是在给线程传递一个中断的限号,程序可以根据此信号来判断是否需要终止。是否要终止取决于程序中的处理。

这个标志位是系统帮助我们设置的

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

class MyThread implements Runnable{
    @Override
    public void run() {
        int i = 1;
        while (true) {
            boolean flag=Thread.currentThread().isInterrupted();
            System.out.println(Thread.currentThread().getName() + "第" + i + "次执行。。。");
            System.out.println(flag);
            i++;
            if(flag){
                System.out.println("线程退出");
                break;
            }
        }
    }
}


public class Test {
    public static void main(String[] args)throws InterruptedException {
        MyThread mt=new MyThread();
        Thread thread=new Thread(mt,"A");
        thread.start();
        thread.sleep(3000);
        thread.interrupt();
    }

}
           

当线程中使用wait 、sleep、join三个方法引起的阻塞,那么会将线程的中断标志重新设置false,并抛出一个InterruptedException;

并且将线程的中断状态由true置为false。

我们要知道,我们的interrupt只是将我们的状态改变,并不会将线程退出,如果要将线程退出,我们要做的就是将在线程中断标志改变之后,所改变后的状态要如何处理。