java runnable开始_Java并发编程之线程创建和启动(Thread、Runnable、Callable和Future)

这一系列的文章暂不涉及Java多线程开发中的底层原理以及JMM、JVM部分的解析(将另文总结),主要关注实际编码中Java并发编程的核心知识点和应知应会部分。

说在前面,Java并发编程的实质,是线程对象调用start方法启动多线程,而线程对象则必须是Thread类或其子类实现。Runnable和Callable的作用类似于Comparable、Serializable,是用于被并发的类实现的接口,从而使得Thread类可以在初始化时传入这个被并发的类。此是大前提。本文从多线程实现和启动出发,对这些类或接口予以说明。

Thread

通过Thread的子类创建多线程的步骤如下:

1. 创建Thread的子类,并重写run()方法,该方法即为线程执行体。

2. 创建Thread子类的对象,即为线程对象。

3. 调用线程对象的start()方法启动线程。

1 public class TestThread extendsThread{2

3 publicTestThread(String name) {4 setName(name);5 }6 @Override7 public voidrun() {8 while(!interrupted())9 System.out.println(getName() + "线程执行了");10 }11 public static voidmain(String[] args) {12

13 TestThread t1 = new TestThread("first");14 TestThread t2 = new TestThread("second");15 //setDaemon()设置线程为守护线程16 //t1.setDaemon(true);17 //t2.setDaemon(true);

18 t1.start();19 t2.start();20 t1.interrupt();21 }22 }

Runnable

需要并发执行的类,可以通过实现Runnable接口,作为Thread的Target来创建线程对象。

1 public class TestRunnable implementsRunnable{2

3 @Override4 public voidrun() {5 while(true) {6 System.out.println("thread running...");7 try{8 Thread.sleep(1000);9 } catch(InterruptedException e) {10 e.printStackTrace();11 }12 }13 }14

15 public static voidmain(String[] args) {16 //传入TestRunnable对象作为Target, 开启线程

17 Thread t = new Thread(newTestRunnable());18 t.start();19 //采用匿名内部类的方式创建和启动线程

20 newThread() {21 @Override22 public voidrun() {23 System.out.println("Thread的匿名内部类");24 }25 }.start();26 //父类采用匿名实现Runnable接口, 并由子类继承

27 new Thread(newRunnable() {28

29 @Override30 public voidrun() {31 System.out.println("父类的线程");32 }33 }) {34 @Override35 public voidrun() {36 System.out.println("子类的线程");37 }38 }.start();39 }40 }

Callable和Future

Java5开始提供了Callable接口,用于现有多线程开发的强力补充。Callable接口提供一个call()方法来构造线程执行体。

1. call()方法可以有返回值

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

因此Callable接口没有继承Runnable接口,不能直接作为Thread类的Target来构造线程对象,所以Java5提供了Future接口来代表call方法的返回值。

Future提供了FutureTask实现类,该实现类实现了Future接口和Runnable接口,像桥梁一样把线程执行体和线程对象连接了起来。

Future接口提供了若干公共方法来操作Callable任务:

boolean cancel(boolean mayInterruptIfRunning): 试图取消Future里关联的Callable任务

V get():返回Callable任务里call方法的返回值。调用该方法会导致阻塞,必须等子线程完成后才得到返回值

V get(long timeout, TimeUnit unit):最多阻塞timeout和unit指定的时间,超时将抛出TimeoutException异常

boolean isCancelled():Callable任务正常完成前被取消,则返回true

boolean isDone():Callable任务已完成,则返回true

创建并启动有返回值的线程步骤如下:

1. 创建Callable接口的实现类,并实现call方法作为线程执行体,再创建类的实例。Java8中可通过Lambda表达式进行。

2. 使用FutureTask类来包装Callable实现类的对象

3. 使用FutureTask作为Thread对象的target

4. 使用FutureTask对象的get方法获取子线程执行后的返回值

Callable接口和FutureTask实现类的底层是基于接口回调技术实现,具体可参考:基于接口回调详解JUC中Callable和FutureTask实现原理

1 public class TestCallable implements Callable{2 //实现Callable并重写call方法作为线程执行体, 并设置返回值1

3 @Override4 public Integer call() throwsException {5 System.out.println("Thread is running...");6 Thread.sleep(3000);7 return 1;8 }9

10 public static void main(String[] args) throwsInterruptedException, ExecutionException {11 //创建Callable实现类的对象

12 TestCallable tc = newTestCallable();13 //创建FutureTask类的对象

14 FutureTask task = new FutureTask<>(tc);15 //把FutureTask实现类对象作为target,通过Thread类对象启动线程

16 newThread(task).start();17 System.out.println("do something else...");18 //通过get方法获取返回值

19 Integer integer =task.get();20 System.out.println("The thread running result is :" +integer);21 }22 }

总结一下,虽然继承Thread类的开发方式相对简单,但因为Java单继承的限制,一般建议通过实现Runnable或Callable接口来创建并启动多线程。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值