21. 实现多线程的两种方法:Thread与Runnable

2016/9/30 21:28 下午 posted in  Java comments

实现多线程在java中有三种方法,前两种比较常用。

继承Thread

1)继承Thread类,重写run方法

class MyThread extends Thread {
    @Override
    public void run(){
        
    }
}

实现Runnable

2)实现Runnable接口
1.重写run方法,实例化后,再创建一个Thread的对象,将其传入Thread(object)方法中
2.创建一个Thread对象,使用匿名内部类实现Runnable接口。

Runnable接口中只声明了一个方法,返回类型为void。

public interface Runnable {
    public abstract void run();
}
class MyThread implements Runnable {
    @Override
    public void run(){
        System.out.println("runnable");
    }
}

class Main {
    public static void main(String[] args) {
        MyThread th = new MyThread();
        Thread run = new Thread(th);
        Thread run2 = new Thread(new Runnable(){
            public void run(){
                System.out.println("inner runnable");
            }
        });
        
        run.start();
        run2.start();
    }
}

实现Callable

3)实现Callable()接口,重写Call方法。
前两种创建线程的方式都包含一个缺陷,在执行完任务后无法获得执行结果。如果要获取执行结果,就必须通过共享变量或者使用线程通信的方式来达到效果。

Callable接口位于java.util.concurrent下,只包含一个方法。

public interface Callable<V> {
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    V call() throws Exception;
}

Callable一般配合ExecutorService接口中的submit方法来使用。

<T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task, T result);
Future<?> submit(Runnable task);

Future

java.util.concurrent
Future用于对具体的Runnable或者Callable任务的执行结果进行取消、查询是否完成、获取结果。可以通过get()获取其执行结果,这个方法或阻塞知道获得任务返回的结果。

public interface Future<V> {

    boolean cancel(boolean mayInterruptIfRunning);

    boolean isCancelled();

    boolean isDone();

    V get() throws InterruptedException, ExecutionException;

    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}
  • cancel用来取消任务,若取消成功则返回true,取消失败则返回false。mayInterruptIfRunning用于表示是否取消(中断)正在执行却没有完成的任务,true表示可以取消。任务未开始执行和任务执行完成时,无论其值为true或false,都返回false,取消失败。若果任务正在执行,其值为true,则返回true,其值为false,则返回fasle。

  • isCancelled()用来查看任务是否被取消成功,取消成功返回true否则false。

  • isDone()用来判断任务是否执行完。

  • get()用来获取执行结果。

  • get(timeout, unit)用来在执行时间内获取结果,超时返回null。

由此可见,Future接口提供了三种功能:
1.判断任务是否完成。
2.设定是否中断任务。
3.可以获取任务的执行结果。

FutureTask

FutureTask是RunnableFuture接口一种实现:

public class FutureTask<V> implements RunnableFuture<V>

RunnableFuture接口继承了Runnable和Future接口,FutureTask实现了Runnable接口,它可以作为Runnable接口的实现被线程执行,又可以作为Future得到Callable的返回值。

public interface RunnableFuture<V> extends Runnable, Future<V> {
    /**
     * Sets this Future to the result of its computation
     * unless it has been cancelled.
     */
    void run();
}

FutureTask有两个构造器方法,分别可以使用Callable和Runnable的实现。

public FutureTask(Callable<V> callable) {
}
public FutureTask(Runnable runnable, V result) {
}

使用方法

1)Callable+Future

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class Test {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newCachedThreadPool();
        Task task = new Task();
        Future<String> result = executor.submit(task);
        executor.shutdown();
         
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }
         
        System.out.println("main process is running");
         
        try {
            System.out.println("result:"+result.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
         
        System.out.println("all tasks finished");
    }
}
class Task implements Callable<String>{
    @Override
    public String call() throws Exception {
        System.out.println("sub process is running");
        Thread.sleep(3000);
        
        return "String result from call";
    }
}

2)Callable+FutureTask
FutureTask提供了使用Callable和Runnable两种实现。

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

public class Test {
    public static void main(String[] args) {
        //1.Callable+FutureTask
        ExecutorService executor = Executors.newCachedThreadPool();
        Task task = new Task();
        FutureTask<String> ft = new FutureTask<String>(task);
        executor.submit(task);
        executor.shutdown();
        
        //2.Callable+FutureTask+Thread
        Task task = new Task();
        FutureTask<String> ft = new FutureTask<String>(task);
        Thread th = new Thread(ft);
        th.start();
         
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }
         
        System.out.println("main process is running");
         
        try {
            System.out.println("result:"+ft.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
         
        System.out.println("all tasks finished");
    }
}
class Task implements Callable<String>{
    @Override
    public String call() throws Exception {
        System.out.println("sub process is running");
        Thread.sleep(3000);
        
        return "String result from call";
    }
}

Callable接口与Runnable接口类似,区别如下:

Callable Runnable
返回值 提供 不提供
抛出异常 call()可以 run()不可以
异步计算结果 检查计算是否完成。 Future对象的get方法,阻塞线程