天天看點

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隻是将我們的狀态改變,并不會将線程退出,如果要将線程退出,我們要做的就是将線上程中斷标志改變之後,所改變後的狀态要如何處理。