前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java--线程的创建和启动

Java--线程的创建和启动

作者头像
SuperHeroes
发布2018-05-22 16:15:57
5190
发布2018-05-22 16:15:57
举报
文章被收录于专栏:云霄雨霁云霄雨霁

上一篇:进程和线程的基本概念

线程的创建有三种方法:继承Thread、实现Runnable接口、使用Callable和Future.

1、继承Thread类创建线程类

步骤如下:

  1. 定义Thread类的子类,并重写该类的run()方法,该run()方法的方法体就代表了线程需要完成的任务,因此把run()方法称为线程执行体。
  2. 创建Thread子类的实例,即创建了线程对象。
  3. 调用线程对象的start()方法来启动线程。
代码语言:javascript
复制
public class FirstThread extends Thread{//继承Thread类
	private int i;
	public void run() {
		for(;i<100;i++)
			System.out.println(getName()+" "+i);
	}
	public static void main(String[] args){
		new FirstThread().start();//创建并启动第一个线程
		new FirstThread().start();//创建并启动第二个线程
	}
}

虽然上面程序只显式地创建了两个线程,但实际上程序有三个线程,即两个子线程和一个主线程。当Java运行时,程序至少创建一个主线程,该主线程的执行体不是由run()方法确定的,而是由main()方法确定。

使用继承Thread类的方法创建线程类时,多个线程之间无法共享线程类的实例变量。如下图所示,Thread-0线程和Thread-1线程都是从0计数开始(共享进程类的实例变量i )。

程序可以通过setName(String name)为线程设置名字,也可以通过getName()方法返回线程的名字。在默认情况下,主线程名字为main,其他线程名字依次为Thread-0、Thread-1、...、Thread-n。

currentThread()是Thread()类的静态方法,该方法返回当前正在执行的线程对象。

2、实现Runnable接口创建线程类

步骤如下:

  1. 定义Runnable接口的实现类,并重写该接口的run()方法。
  2. 创建Runnable实现类的实例,并以此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象。
  3. 调用start()方法来启动线程。

注:Java 8 增加了lambda(λ)表达式,因为Runnable接口是函数式接口,所以可以直接使用lambda表达式来创建Runnable对象。

代码语言:javascript
复制
public class SecondThread implements Runnable{
	private int i;
	@Override
	public void run() {
		// TODO Auto-generated method stub
		for(;i<100;i++)
			System.out.println(Thread.currentThread()+" "+i);
	}
	public static void main(String[] args){
		SecondThread st = new SecondThread();
		new Thread(st,"新线程1").start();
		new Thread(st,"新线程2").start();
	}
}

采用Runnable接口的方式创建的多个线程可以共享线程类的实例变量。如下图所示,新线程1和新线程2是累加的关系。

Runnable对象仅仅作为Thread对象的target,Runnable实现类中的run()方法仅仅作为线程执行体。而世纪的线程对象依然是Thread实例,只是该Thread线程负责执行其target的run()方法。正因为程序所创建的Runnable对象只是线程的target, 而多个线程可以共享同一个target,所以多个线程可以共享同一个线程类(实际上应该是线程的target类)的实例变量。

3、使用Callable和Future创建线程类

上面已经指出,通过Runnable接口创建线程时,Thread类的作用是把run()方法包装成线程执行体。那么可不可以直接把任意方法包装成线程执行体呢?Java目前不行。(C#可以)

但是从Java 5开始,Java提供了Callable接口,该接口提供一个call()方法作为线程执行体,并且可以有返回值,还可以声明抛出异常。这很像Runnable接口的增强版,因此可以想出使用Callable对象作为Thread的target。问题是:Callable接口不是Runnable的自接口,因此不能直接作为Thread的target。

Java 5同时提供了Future接口来代表Callable接口里的call()方法的返回值,并为Future接口提供了一个FutureTask实现类,该类实现了Callable接口和Runnable接口,可以作为Thread的target使用。

步骤如下:

  1. 创建Callable接口的实现类,实现call()方法,再创建Callable实现类的实例。(Callable接口也是函数式接口,可以使用lambda表达式)
  2. 使用FutureTask类包装Callable对象,该FutureTask对象封装了Callable对象的call()方法的返回值。
  3. 使用FutureTask对象作为Thread对象的target,创建并启动线程。
  4. 调用FutureTask对象的gat方法来获得子线程执行结束后的返回值。
代码语言:javascript
复制
public class ThirdThread {
	public static void main(String[] args) {
		ThirdThread rt = new ThirdThread();
		FutureTask<Integer> task = new FutureTask<Integer> (Callable<Integer>)()->{//lambda表达式
			int i = 0;
			for(;i<100;i++)
				System.out.println(Thread.currentThread()+" "+i);
		});
		new Thread(task,"有返回值的线程").start();
		try {
			System.out.print("子线程返回的值"+task.get());
		}catch(Exception ex) {
			ex.printStackTrace();
		}
	}
}

Future接口定义了如下几个共有方法:

  • boolean cancel(boolean mayInterruptIfRunning):试图取消Future里关联的Callable。
  • V get():返回Callable任务里call()方法的返回值。调用该方法将导致程序阻塞,必须等到子程序结束后才能得到返回值。
  • V get(long timeout, TimeUnit unit):返回Callable任务里call()方法的返回值。该方法让程序最多阻塞timeout和unit指定的时间,如果超出时间Callable任务依然没有返回值,抛出TimeoutException异常。
  • boolean isCancelled():如果在Callable任务正常完成前被取消,则返回true。
  • boolean isDone():如果Callable任务已完成,则返回true。

创建线程的三种方式对比:

采用Runnable、Callable接口实现多线程:

  • 线程类只是实现了接口,还可以继承其他类;
  • 多个线程可以共享同一个target对象,非常适合多个相同线程来处理同一份资源的情况;
  • 劣势是,变成稍微复杂,如果想访问当前线程,需要使用Thread.currentThread()方法。

采用继承Thread类实现:

  • 劣势是,因为继承了Thread类,无法继承其他类;
  • 优势是,编程简单。

综上,一般推荐使用实现接口的方式来创建多线程。

下一篇----五态模型&线程控制

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1、继承Thread类创建线程类
  • 2、实现Runnable接口创建线程类
  • 3、使用Callable和Future创建线程类
  • 创建线程的三种方式对比:
  • 下一篇----五态模型&线程控制
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档