java中如何使用线程
java中创建线程的几种方法:
- 创建线程(Thread实例)的方式一:继承Thread类创建线程类,让后创建线程实例
- 创建线程(Thread实例)的方式二:实现Runnable接口创建线程目标类,让后创建线程实例
- Future接口和FutureTask异步任务类
- 使用Callable和FutureTask创建异步任务,让后创建线程实例
- 通过线程池创建线程
继承Thread类创建线程类,让后创建线程实例流程
1).需要继承Thread类,创建一个新的线程子类
2).同时重写run()方法,把需要并发执行的业务代码放入run方法中
代码实现:
public class CreateDemo {
static int ThreadName = 1;
//继承Thread类
static class ThreadDemo extends Thread {
public ThreadDemo() {
super("线程-" + ThreadName++);
}
//重写run方法,业务逻辑代码写在方法里
@Override
public void run() {
for (int i = 1; i <= 5; ++i) {
System.out.println(this.getName() + " 第" + i + "次执行");
}
System.out.println(this.getName() + " 运行结束");
}
}
public static void main(String[] args) {
Thread thread = null;
for (int i = 0; i < 2; ++i) {
thread = new ThreadDemo();
thread.start();
}
}
}
实现Runnable接口创建线程目标类,让后创建线程实例流程
1.定义一个新类实现Runnable接口
2.实现Runnable接口中的run()抽象方法,将线程代码逻辑存放在该run()实现版本中
3.通过Thread类创建线程对象,将Runnable的实现类实例,作为实际参数传递给Thread类的构造器。由Thread构造器将该Runnable实例赋值给自己的target执行目标属性
4.调用Thread实例的start方法,开启线程
代码实现:
public class CreateDemo2 {
static int ThreadName = 1;
//实现Runnable接口
static class RunTarget implements Runnable {
//写业务逻辑代码
@Override
public void run() {
for (int i = 1; i <= 5; ++i) {
System.out.println(Thread.currentThread().getName() + " 第" + i + "次执行");
}
System.out.println(Thread.currentThread().getName() + " 运行结束");
}
}
public static void main(String[] args) {
Thread thread = null;
//方式一:使用实现Runnable的实现类,创建和启动线程
for (int i = 1; i <= 2; ++i) {
thread = new Thread(new RunTarget(), "线程-" + ThreadName++);
thread.start();
}
//方式二:使用匿名内部类,创建和启动线程
for (int i = 1; i <= 2; ++i) {
thread = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 1; i <= 5; ++i) {
System.out.println(Thread.currentThread().getName() + " 第" + i + "次执行");
}
System.out.println(Thread.currentThread().getName() + " 运行结束");
}
},"方式二 线程-" + ThreadName++);
thread.start();
}
}
}
Runnable异步任务的问题:
- 不能获取异步执行的目标结果(方法没有返回值)
- 不能取消异步执行的任务
解决方法:
- 使用“可以进行管理的异步任务”相关类,Future接口和FutureTask异步任务类
FutureTask类的UML关系图
使用Callable和FutureTask创建异步任务,让后创建线程实例流程
1.创建一个Callable接口的实现类,并实现其call()方法,编写好异步执行的相关逻辑,并且可以由返回值
2.使用Callable实现类的实例,构造一个FutureTask实例
3.使用FutureTask实例,作为Thread构造器的target入参,构造新的Thread线程实例
4.调用Thread实例的start()方法启动新线程,启动新线程的run()方法并执行。其内部的执行过程为:启动Threa实例的run()方法并发执行后,会执行FutureTask实例的run()方法,最终会并发执行Callable实现类中的call()方法。
5.调用FutureTask对象的get()方法,阻塞性的获得并发线程的执行结果
public class CreateDemo3 {
static class RunnableTask implements Callable<Long> {
@Override
public Long call() throws Exception {
//获取执行前的时间
long start = System.currentTimeMillis();
System.out.println(Thread.currentThread().getName() + " 开始运行");
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + " 运行结束");
long end = System.currentTimeMillis() - start;
return end;
}
}
public static void main(String[] args) {
RunnableTask runnableTask = new RunnableTask();
FutureTask<Long> futureTask = new FutureTask<>(runnableTask);
Thread thread = new Thread(futureTask, "线程");
thread.start();
//阻塞的获取异步执行的结果
try {
System.out.println("异步执行的结果为:线程执行" + futureTask.get() + "ms");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
FutureTask可以处于三种状态
1. 未启动: 在FutureTask.run()还没执行前,FutureTask处于未启动状态。在创建后并且为执行run()方法前。
2. 已启动: Future Task对象的run方法启动并执行过程中,FutureTask处于已启动状态。
3. 已完成: FutureTask正常执行结束,或者FutureTask执行被取消(FutureTask对象的cancel方法),或者FutureTask方法执行抛出异常而导致中断而结束,FutureTask都处于已完成状态。FutureTask三种状态图解
线程只有处于已完成状态时,调用get()方法才会返回异步执行的结果,处于其它状态时,调用get()方法会阻塞。
通过线程池创建线程流程
线程池的内容比较多,单独写道另一篇文章里面了。