Java 范例 - 线程

创建线程

Java 中有以下三种方式创建线程,其中前两种无法获取返回值,而最后一种可以获取返回值。

  • 实现 Runnable 接口
  • 继承 Thread 类
  • 通过 Callable、Future 接口配合

实现 Runnable 接口

可以声明一个类实现 Runnable 接口,接着在重写的 run() 方法中编写线程中执行的代码。

class RunnableThread implements Runnable {
    @Override
    public void run() {
        // ...
    }
}

接着实例化该类,并作为 Thread 类的构造器参数传入。

Thread runnableThread = new Thread(new RunnableThread());

继承 Thread 类

与实现 Runnable 接口相同,继承也需要重写 run() 方法。

class ExtendThread extends Thread {
    @Override
    public void run() {
        // ...
    }
}

不过这种方式创建线程,直接实例化类就可以了。

Thread extendThread = new ExtendThread();

通过 Callable、Future 接口配合

先声明一个类继承 Callable 接口,其中接口中的泛型为返回值的类型,线程中的执行代码在重写的 call() 方法中。

public class ReturnThread implements Callable<String> {
	@Override
	public String call() {
	    // ...
		return "return value";
	}
}

实例化该类,将其提交到线程池(线程池篇会提及)中运行,然后可以通过 get() 方法来获取返回值。

Callable<String> returnThread = new ReturnThread();
Future<String> returnValue = executor.submit(returnThread);
returnValue.get();

FutureTask 类

当通过 submit() 方法向线程池提交任务时,当前线程会阻塞直到返回结果,为了满足不阻塞的需求就有了 FutureTask 类。将上面继承 Callable 接口的类用 FutureTask 类包装后,在提交至线程池中运行。

由于 FutureTask 类实现了 RunnableFuture 接口,而 RunnableFuture 接口继承了 Runnable 和 Future 接口,所以也可以用 get() 方法来获取返回值。

FutureTask<String> futureTask = new FutureTask<>(returnThread);
executor.submit(futureTask);
// Unblock, so can do something here
futureTask.get();

线程的状态及转换

Java 线程有以下七种状态,但除去创建状态和终止状态,就只有和操作系统课程中进程一样的三类状态,分别是就绪、运行和阻塞。

  • 创建状态(new),线程创建完毕
  • 就绪状态(runnable),线程所需资源准备完毕
  • 运行状态(running),线程获得处理机时间
  • 终止状态(dead),线程执行完毕或异常中断
  • 阻塞状态(blocked),线程被同步阻塞或者 IO 阻塞
  • 超时等待(time waiting),线程主动睡眠指定时间
  • 等待阻塞(waiting),线程主动等待

上文创建线程例子中(除开线程池提交例子),当用 new 关键字创建好线程后,线程就进入了创建状态,可以用 start() 方法让线程进入就绪状态(前提是线程所需资源准备完毕),接着就可以等待的调度进入运行状态,然后线程运行完之后进入终止状态。

当线程遇到同步或者 IO 时就会进入阻塞状态,调用 join() 方法可以让线程主动等待另一线程线程执行完毕,而线程中调用 sleep() 方法就可以让线程主动睡眠指定的一段时间,以下为线程状态转换状态图。

new --> runnable <---> running --> dead
         |                ^
         |                |
         *---> blocked ---*
         |                |
         |                |
         *---> waiting ---*
         |                |
         |                |
         *-> time waiting *

Thread 类常用方法

下面列出了 Thread 类中常用的方法。

// 让线程进入就绪状态
start()

// 线程主动睡眠指定时间
sleep(long millis)
sleep(long millis, int nanoseconds)

// 线程让出处理机时间,给同优先级的线程
// 注意该方法让线程重回就绪状态,而不是阻塞状态
yield()

// 等待线程执行完毕,或者等待指定时间
join()
join(long millis)
join(long millis, int nanoseconds)

// 中断处于阻塞状态的线程,注意不能中断正在运行中的线程
interrupt()

// 获取线程标识符
getID()

// 获取设置线程名称
getName()
setName()

// 获取设置线程优先级
getPriority()
setPriority()

// 设置线程是否为守护线程
setDaemon()
// 判断是否为守护线程
isDaemon()
posted @ 2019-03-22 22:40  ZachLim  阅读(187)  评论(0编辑  收藏  举报