【Java基础】:线程的创建和启动

原创 2016年08月30日 16:58:36

        单线程的程序在实际情况中,往往功能是十分有限的,因此随着业务逻辑的复杂度增加好程序并发量的增大,就引入了多线程的概念。Java语言提供了非常优秀的多线程技术支持,程序可以通过非常简单的方式来创建新的线程并启动之。

        Java使用Thread类代表线程,所有的线程对象都必须是Thread类或其子类的实例。通常有三种方式来创建新的线程。

        大家都比较熟悉的是前两种方式,一种是通过继承Thread类来创建,另一种是通过实现Runnable接口来创建。因为这两种方式大家都比较熟悉,我也就不在这里去详细说明如何实现了,直接看第三种方式是什么。

        第三种方式:使用Callable和Future创建线程

        从Java 5开始,Java提供了Callable接口,熟悉的人可能会感觉和Runnable接口有点像,可以认为是Callable接口的增强版,Callable接口提供了一个call()方法作为线程执行体,但是要注意的是call()方法比run()方法功能更加强大。具体体现在两点:

        1call方法可以有返回值

        2call方法可以声明抛出异常

        因此完全可以提供一个Callable对象作为Thread的target,而该线程的线程执行体就是该Callable对象的call方法。问题是:Callable接口使Java 5新增的接口,而且它不是Runnable接口的子接口,所以Callable对象不能直接作为Thread的target。而且call方法还有一个返回值——call方法并不是直接调用,它是作为线程执行体被调用的。那么如何获取call方法的返回值呢?

        Java5提供了Future接口来代表Callable接口里的call方法的返回值,并为Future接口提供了一个FutureTask实现类,该实现类实现了Future接口,并且实现了Runnable接口——可以作为Thread类的target。

        在Future接口里定义了如下几个公共方法来控制它关联的Callable任务。

public interface Future<V> {

    /**
     * Attempts to cancel execution of this task.  This attempt will
     * fail if the task has already completed, has already been cancelled,
     * or could not be cancelled for some other reason. If successful,
     * and this task has not started when {@code cancel} is called,
     * this task should never run.  If the task has already started,
     * then the {@code mayInterruptIfRunning} parameter determines
     * whether the thread executing this task should be interrupted in
     * an attempt to stop the task.
     *
     * <p>After this method returns, subsequent calls to {@link #isDone} will
     * always return {@code true}.  Subsequent calls to {@link #isCancelled}
     * will always return {@code true} if this method returned {@code true}.
     *
     * @param mayInterruptIfRunning {@code true} if the thread executing this
     * task should be interrupted; otherwise, in-progress tasks are allowed
     * to complete
     * @return {@code false} if the task could not be cancelled,
     * typically because it has already completed normally;
     * {@code true} otherwise
     */
    boolean cancel(boolean mayInterruptIfRunning);

    /**
     * Returns {@code true} if this task was cancelled before it completed
     * normally.
     *
     * @return {@code true} if this task was cancelled before it completed
     */
    boolean isCancelled();

    /**
     * Returns {@code true} if this task completed.
     *
     * Completion may be due to normal termination, an exception, or
     * cancellation -- in all of these cases, this method will return
     * {@code true}.
     *
     * @return {@code true} if this task completed
     */
    boolean isDone();

    /**
     * Waits if necessary for the computation to complete, and then
     * retrieves its result.
     *
     * @return the computed result
     * @throws CancellationException if the computation was cancelled
     * @throws ExecutionException if the computation threw an
     * exception
     * @throws InterruptedException if the current thread was interrupted
     * while waiting
     */
    V get() throws InterruptedException, ExecutionException;

    /**
     * Waits if necessary for at most the given time for the computation
     * to complete, and then retrieves its result, if available.
     *
     * @param timeout the maximum time to wait
     * @param unit the time unit of the timeout argument
     * @return the computed result
     * @throws CancellationException if the computation was cancelled
     * @throws ExecutionException if the computation threw an
     * exception
     * @throws InterruptedException if the current thread was interrupted
     * while waiting
     * @throws TimeoutException if the wait timed out
     */
    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}public interface Future<V> {

    /**
     * Attempts to cancel execution of this task.  This attempt will
     * fail if the task has already completed, has already been cancelled,
     * or could not be cancelled for some other reason. If successful,
     * and this task has not started when {@code cancel} is called,
     * this task should never run.  If the task has already started,
     * then the {@code mayInterruptIfRunning} parameter determines
     * whether the thread executing this task should be interrupted in
     * an attempt to stop the task.
     *
     * <p>After this method returns, subsequent calls to {@link #isDone} will
     * always return {@code true}.  Subsequent calls to {@link #isCancelled}
     * will always return {@code true} if this method returned {@code true}.
     *
     * @param mayInterruptIfRunning {@code true} if the thread executing this
     * task should be interrupted; otherwise, in-progress tasks are allowed
     * to complete
     * @return {@code false} if the task could not be cancelled,
     * typically because it has already completed normally;
     * {@code true} otherwise
     */
    boolean cancel(boolean mayInterruptIfRunning);

    /**
     * Returns {@code true} if this task was cancelled before it completed
     * normally.
     *
     * @return {@code true} if this task was cancelled before it completed
     */
    boolean isCancelled();

    /**
     * Returns {@code true} if this task completed.
     *
     * Completion may be due to normal termination, an exception, or
     * cancellation -- in all of these cases, this method will return
     * {@code true}.
     *
     * @return {@code true} if this task completed
     */
    boolean isDone();

    /**
     * Waits if necessary for the computation to complete, and then
     * retrieves its result.
     *
     * @return the computed result
     * @throws CancellationException if the computation was cancelled
     * @throws ExecutionException if the computation threw an
     * exception
     * @throws InterruptedException if the current thread was interrupted
     * while waiting
     */
    V get() throws InterruptedException, ExecutionException;

    /**
     * Waits if necessary for at most the given time for the computation
     * to complete, and then retrieves its result, if available.
     *
     * @param timeout the maximum time to wait
     * @param unit the time unit of the timeout argument
     * @return the computed result
     * @throws CancellationException if the computation was cancelled
     * @throws ExecutionException if the computation threw an
     * exception
     * @throws InterruptedException if the current thread was interrupted
     * while waiting
     * @throws TimeoutException if the wait timed out
     */
    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

        cancel(booleanmayInterruptIfRunning):试图取消该Future里关联的Callable任务。

        Vget():返回Callable任务里call方法的返回值,调用该方法将导致程序阻塞,必须等到子线程结束后才会得到返回值。

        Vget(long timeOut, TimeUnit unit):返回Callable任务里call方法的返回值,该方法让程序最多阻塞timeout和unit指定的时间,如果经过指定时间后Callable任务依然没有返回值,将会抛出TimeoutException异常。

        BooleanisCancelled():如果在Callable任务正常完成前被取消,则返回true。

        BooleanisDone():如果Callable任务已经完成,则返回true。

        需要注意的是,Callable接口有泛型限制,Callable接口里的泛型形参类型与call方法返回值类型相同。而且Callable接口使函数式接口,因此可以使用Lambda表达式创建Callable对象。

      下面我们就通过代码来看如何使用Callable和Future来创建并且启动线程:

public class ThirdThread
{
	public static void main(String[] args)
	{
		// 创建Callable对象
		ThirdThread rt = new ThirdThread();
		// 先使用Lambda表达式创建Callable<Integer>对象
		// 使用FutureTask来包装Callable对象
		FutureTask<Integer> task = new FutureTask<Integer>((Callable<Integer>)() -> {
			int i = 0;
			for ( ; i < 100 ; i++ )
			{
				System.out.println(Thread.currentThread().getName()
					+ " 的循环变量i的值:" + i);
			}
			// call()方法可以有返回值
			return i;
		});
		for (int i = 0 ; i < 100 ; i++)
		{
			System.out.println(Thread.currentThread().getName()
				+ " 的循环变量i的值:" + i);
			if (i == 20)
			{
				// 实质还是以Callable对象来创建、并启动线程
				new Thread(task , "有返回值的线程").start();
			}
		}
		try
		{
			// 获取线程返回值
			System.out.println("子线程的返回值:" + task.get());
		}
		catch (Exception ex)
		{
			ex.printStackTrace();
		}
	}
}

        上面程序中使用了Lambda表达式直接创建了Callable对象,这样就无须先创建Callable实现类,再创建Callable对象了。实现Callable接口与实现Runnable接口并没有太大的区别,只是Callable的call方法允许声明抛出异常,而且允许带返回值。
版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

java线程的创建于启动

  • 2012年05月17日 17:00
  • 19KB
  • 下载

java 多线程基础(一)——线程创建及五种状态

最近在使用SOA的模式重构搞笑平台,在考试系统模块,期望使用上多线程,之前对多线程有过一些了解,不过具体的实现是在.net平台下的。虽然一年前接触过j2se的关于多线程的一些知识,但是感觉还是不够,于...
  • lmdcszh
  • lmdcszh
  • 2013年12月31日 20:12
  • 2935

【java并发】基础(1)--创建线程的两种方法

一、常用的两种方法创建线程的两种方法: 继承Thread类(java.lang.Thread) 实现Runnable接口(java.lang.Runnable) 1.1 继承Thread类public...

线程创建的两种方式02--Java基础068

package com.sqf.thread; //需求: 模拟3个窗口同时在售50张 票 。 public class SaleTicket1 implements Runnable{ i...

Java多线程基础,线程的创建使用以及终止

我们在使用多任务操作系统时,比如windows,可以一边聊着qq,一边听着音乐,一边玩着游戏等等,这一个个的程序就是一个个进程,而每个进程里至少有一个线程在执行任务,比如,qq,有个线程在执行文件下载...

Java多线程基础学习之线程的创建方式总结

话不多说,咱们直入主题!首先罗列出创建线程的三种方式: 通过继承Thread类,覆写run()方法创建线程类 通过实现Runnable接口,实现run()方法创建类,作为Thread的construc...
  • Hong_A
  • Hong_A
  • 2017年03月08日 16:26
  • 144

Java基础:多线程之线程创建的两种方式

创建线程有两种方式: 1. 继承Thread类,覆写run方法; 2. 实现Runnable接口,将任务代码封装到run方法中。...

Java基础学习----不同种创建线程的区别

今天看了基础视频的线程,发现以前看书学到的东西好少,下面跟大家分享一下,说得多多指教,开始吧! 两种创建线程的方法及区别 两种创建线程的方法: 1.继承Thread类,格式:class  线程名...

java线程基础

  • 2013年03月01日 20:31
  • 281KB
  • 下载

java线程基础(IBM教程)

  • 2008年09月20日 17:49
  • 408KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:【Java基础】:线程的创建和启动
举报原因:
原因补充:

(最多只允许输入30个字)