Java线程创建并运行的三种方式:Thread,Runnable,Callable

1、用Thread创建线程:继承Thread类,重写Thread类的run()方法,用Thread子类的实例调用start()方法就开启了一个运行run()函数的线程。

1.1可以直接创建一个子类,用子类实例调用start()方法:

public class MyClassThread  extends Thread {
    public void run(){
        System.out.println(Thread.currentThread().getName());
    }
}

启动线程时可以:
new MyClassThread().start();

1.2可以创建一个匿名子类:

new Thread(){
            public void run(){
                System.out.println("匿名子类");
            }
        }.start();


2、用Runnable创建线程:实现TRunnable接口,重写Runnable接口的run()方法,用实现类的实例调用start()方法就开启了一个运行run()函数的线程。

2.1可以创建一个实现Runnable接口的类,让其实例调用start()方法:

public class MyClassRunnable implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}
启动线程时要把实现Runnable类的实例传到Thread的构造器里:
new Thread(new MyClassRunnable()).start();
2.2也可以创建匿名子类:
new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("Runnable匿名子类");
            }
        }).start();
2.3通过创建线程池submit()方法执行Runnable(这种方式可以获得一个返回值):
先看一下submit()源码:
<T> Future<T> submit(Callable<T> task);  
<T> Future<T> submit(Runnable task, T result);  
Future<?> submit(Runnable task);  
示例:
ExecutorService executorService = Executors.newCachedThreadPool();
//用线程池执行Runnable并获取一个返回结果
Future<String> futureRun = executorService.submit(new Runnable() {
	@Override
	public void run() {
		String s = "执行了";
		System.out.println("通过线程池执行Runnable");
			}
		},s);
也可以通过这种方式:
Future futureRun2 = executorService.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println("没有返回结果");
            }
        });
2.4用工厂类Executors静态方法将Runnable封装成Callable,然后用Callable的启动方法去启动。源码:
public static Callable<Object> callable(Runnable task)  
public static <T> Callable<T> callable(Runnable task, T result)
示例:
//将Runnable封装成Callable
        Callable callable = Executors.callable(new Runnable() {
            @Override
            public void run() {
                System.out.println("封装成Callable的Runnable");
            }
        });
        final String[] str = new String[1];
        Callable<String> callable1 = Executors.callable(new Runnable() {
            @Override
            public void run() {
                str[0] = "执行了";
                System.out.println("封装成Callable的Runnable,并且有返回结果");
            }
        },str[0]);


3、Thread和Runnable的比较:
Thread实现了Runnable;
在面向对象思想中,Runnable实例是一个作业,Thread实例才是要执行作业的线程。将作业定义好,传到Thread里,是组合关系,相比于继承Thread,松耦合;
用Thread需要继承,Java中不能多继承,而可以实现多个接口。这是另一个Runnable的好处。
 
4、用Callable创建线程:
4.1 Callable和Runnable的区别:
4.1.1前者通过call()方法设置线程执行任务,后者通过run()方法。
4.1.2Callable的源码:
public interface Callable<V> {
        V call() throws Exception;
    }
可见Callable是一个泛型参数化的接口。call()方法是有返回值而且能抛出异常的,这是比run()方法多的特性。
4.2通过线程池submit()方法执行Callable:Callable不像Runnable接口能把实例放到Thread构造器中,由Thread的start()方法启动。Callable通常当做线程池submit()方法的参数传入以启动,并且submit()方法会返回Future实例,用于对异步计算结果的获取。Future<V>源码:
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;  
}  

(1)当FutureTask处于未启动或已启动状态时,如果此时我们执行FutureTask.get()方法将导致调用线程阻塞;当FutureTask处于已完成状态时,执行FutureTask.get()方法将导致调用线程立即返回结果或者抛出异常。
(2)当FutureTask处于未启动状态时,执行FutureTask.cancel()方法将导致此任务永远不会执行。
当FutureTask处于已启动状态时,执行cancel(true)方法将以中断执行此任务线程的方式来试图停止任务,如果任务取消成功,cancel(...)返回true;但如果执行cancel(false)方法将不会对正在执行的任务线程产生影响(让线程正常执行到完成),此时cancel(...)返回false。
当任务已经完成,执行cancel(...)方法将返回false。
运行Callable示例:
//用Callable(通过线程池)执行线程
        ExecutorService executorService = Executors.newCachedThreadPool();
        Future future = executorService.submit(new Callable<String>() {
            @Override
            public String call() throws Exception {
                String s = "Callable";
                System.out.println(s);
                return s;
            }
        });
4.3将Callable作为参数传入FutureTask构造器中,通过FutureTask执行:事实上FutureTask实现了RunnableFuture<V>接口,而RunnableFuture<V>接口继承了Runnable接口和Future<V>接口,所以FutureTask可以放到Thread的构造器里去运行:
//用Callable(通过FutureTask封装)执行线程
        FutureTask futureTask = new FutureTask(new MyClassCallable());
        Thread thread = new Thread(futureTask);
        thread.start();



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值