Java并发系列:启动和终止线程

/ JavaSE / 201浏览

启动线程

在运行线程之前首先要构造一个线程对象,线程对象在构造的时候需要提供线程的属性,比如线程组、优先级、名字、Daemon状态啊等属性。

一个新构造的线程对象初始化好了,在堆内存中等待着运行。调用 start() 方法就可以启动这个线程。线程的 start() 方法的含义是:当前线程同步告知 Java虚拟机,只要线程规划器空闲,应立即启动调用 start() 方法的线程。

🌔 注意,启动一个线程,最好为这个线程设置线程名称,因为这样在使用 jstack 分析线程或者进行问题排查时,就会给我们提供一些提示。

线程终止

中断可以理解为线程的一个标识位属性,它表示一个运行中的线程是否被其它线程进行了中断。中断好比其它线程对该线程打了个招呼,其他线程通过调用该线程的 interrupt() 方法对其进行中断操作。

线程通过检查自身是否被中断进行响应,线程通过方法 isInterrupted() 来进行判断是否被中断,也可调用静态方法 Thread.interrupted() 对当前线程的中断标识位进行复位。如果该线程已经处于终结状态,即使该线程被中断过,在调用该线程对象的 isInterrupted() 时依旧会返回 false。

如下代码,显示一个终止线程用例:

public class ThreadInterrupt {

    public static void main(String[] args){
        Thread t1 = new Thread(new MyThread(),"精灵线程");
        t1.start();
        try {
            //main线程休眠10毫秒
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //终止精灵线程
        t1.interrupt();
    }
}

class MyThread implements Runnable{
    private long i=0;
    @Override
    public void run() {
        while (!Thread.currentThread().isInterrupted()) {
            i++;
        }
        System.out.println(Thread.currentThread().getName()+" 运行10毫秒,i 值累加结果:"+i);
    }
}

main方法创建了一个名为“精灵线程” t1,休眠10毫秒后,对 t1 线程进行终止。

其输出结果(每次可能都不一样):

精灵线程 运行10毫秒,i 值累加结果:1054662

实现线程3种方式

实现Runable接口

接口需要实现run方法,在run方法体内编写内容,用例代码如下:

package cn.zealon.thread;
import java.util.Date;
/**
 * 实现Runnable接口,需要实现 run() 方法。
 *
 * @auther: Zealon
 *
 */
public class UseRunnable implements Runnable{
    @Override
    public void run() {
        System.out.println("当前线程名称:"+Thread.currentThread().getName()+
                ",时间:"+new Date().toString());
    }

    //运行线程实例
    public static void main(String[] args) {
        UseRunnable instance = new UseRunnable();
        Thread thread = new Thread(instance);
        thread.start();
    }
}

继承Thread类

继承Thread类,需要重写run方法,因为Thread类也实现了Runable 接口,我们可以看下Thread类的定义如下:

/**
 * A <i>thread</i> is a thread of execution in a program. The Java
 * Virtual Machine allows an application to have multiple threads of
 * execution running concurrently.
 * <p>
 * ......
 * @author  unascribed
 * @see     Runnable
 * @see     Runtime#exit(int)
 * @see     #run()
 * @see     #stop()
 * @since   JDK1.0
 */
public class Thread implements Runnable {
    /* Make sure registerNatives is the first thing <clinit> does. */
    private static native void registerNatives();
    static {
        registerNatives();
    }
    ...
}

Thread类相当于封装了一些并发相关的属性以及方法,它自身实现的Runnable接口,所以我们继承Thread类需要重写run方法,用例代码如下:

package cn.zealon.thread;

import java.util.Date;
/**
 * 继承Thread类,需要重写run方法(因为Thread类也实现了Runable 接口).
 *
 * @auther: Zealon
 */
public class UseThread extends Thread{
    @Override
    public void run() {
        System.out.println("当前线程名称:"+Thread.currentThread().getName()+
                ",时间:"+new Date().toString());
    }

    public static void main(String[] args){
        UseThread instance = new UseThread();
        instance.start();
    }
}

实现Callable接口

实现Callable接口,需要实现call方法;与Runnable方式比较,Callable方式有返回值,返回值通过FutureTask进行封装。 用例代码如下:

package cn.zealon.thread;

import java.util.Date;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * 实现Callable接口,需要实现call方法;
 * 与Runnable方式比较,Callable方式有返回值,返回值通过FutureTask进行封装.
 *
 * @auther: Zealon
 * 
 */
public class UseCallable implements Callable<String> {

    @Override
    public String call() {
        return "当前时间:"+new Date().toString();
    }

    public static void main(String[] args){
        UseCallable instance = new UseCallable();
        //封装任务类
        FutureTask<String> futureTask = new FutureTask<String>(instance);
        //创建线程类
        Thread thread = new Thread(futureTask);
        //启动线程
        thread.start();
        try {
            System.out.println(futureTask.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}