1.继承Thread类
- Thread类是Java提供的线程顶级类,继承Thread类可快速定义线程。
【示例1】 使用多线程实现龟兔赛跑
public class TortoiseThread extends Thread {
/**
* 线程体,线程要完成的任务,要执行的代码
*/
@Override
public void run() {
while (true) {
System.out.println("乌龟领先了,加油.....," +
"当前线程的名称:" + this.getName() +
",当前线程的优先级别:" + this.getPriority());
}
}
}
public class Test {
public static void main(String[] args) {
//创建一个线程
TortoiseThread thread = new TortoiseThread();
//启动一个线程
//thread.run();//这不是在启动线程,是在调用方法run()
//启动线程,不见得立刻执行,而是进入就绪队列,等待获得CPU
thread.start();
//兔子也在跑,此处不在单独创建线程并启动
while(true){
System.out.println("兔子领先了,add oil....,当前线程名称:"
+Thread.currentThread().getName()+",当前线程的优先级别:"
+Thread.currentThread().getPriority());
}
}
}
- run()线程体,线程要完成的任务。
- start()启动线程,线程进入就绪队列,等待获取CPU并执行。
- 之前的程序都是单线程的。
2.实现Runnable接口
【示例2】使用多线程实现龟兔赛跑2
public class TortoiseRunnable implements Runnable {
//private int num = 100;
/**
* 线程体,线程要执行的任务
*/
@Override
public void run() {
while(true){
while(true){
System.out.println("乌龟领先了,加油...."+
Thread.currentThread().getName()+" "+
Thread.currentThread().getPriority());
}
}
}
}
public class Test {
public static void main(String[] args) {
//创建乌龟线程对象
//Runnable runnable = new TortoiseRunnable();
Runnable runnable = new Runnable(){
@Override
public void run() {
while(true){
System.out.println("乌龟领先了............"
+Thread.currentThread().getName());
}
}
};
Thread thread1 = new Thread(runnable);
//启动乌龟线程
thread1.start();
Thread thread2 = new Thread(runnable);
thread2.start();
while(true){
System.out.println("兔子领先了,add oil ...."+
Thread.currentThread().getName()+" "+
Thread.currentThread().getPriority());
}
}
}
两种方式的优缺点
方式1:继承Thread类
-
缺点:Java单继承,无法继承其他类
-
优点:代码稍微简单
方式2:实现Runnable接口
-
优点 还可以去继承其他类 便于多个线程共享同一个资源
-
缺点:代码略有繁琐
实际开发中,方式2使用更多一些
- 可以使用匿名内部类来创建线程对象
- 已经学习的线程Thread的属性和方法
3.线程的定义和创建3:实现Callable接口
JDK1.5后推出了第三种定义线程的方式:实现Callable接口。
【示例3】使用多线程获取随机数
package com.bjsxt.create3;
import java.util.Random;
import java.util.concurrent.*;
/**
* com.bjsxt.create3
*
* @author Zhang Yongchang
* @create 2021-04-22
*
* 返回随机数
**/
public class RandomCallable implements Callable<Integer> {
@Override
public Integer call() throws Exception {
// if (true) {
// throw new Exception();
// }
Thread.sleep(6000);
return new Random().nextInt(100);
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
//创建一个线程对象
Callable<Integer> callable=new RandomCallable();
FutureTask<Integer> task = new FutureTask<>(callable);
Thread thread = new Thread(task);
//启动线程
thread.start();
//获取返回值
System.out.println(task.isDone());
//必须等线程执行完毕后,才能得到返回值,线程会在此阻塞
// int result = task.get();//一根筋,得不到返回值就一直等待
int result = 0;
//还没等线程执行完就抛出TimeoutException异常
try {
result = task.get(4, TimeUnit.SECONDS);
} catch (TimeoutException e) {
e.printStackTrace();
}
System.out.println(task.isDone());//线程是否执行完毕
System.out.println(result);
}
}
第三种方式:实现Callable接口
与实现Runnable接口相比,Callable功能更强大一些。
- 方法名不同
- 可以有返回值,支持泛型的返回值
- 可以抛出检查异常
- 需要借助FutureTask,比如获取返回结果
Future接口
- 可以对具体Runnable、Callable任务的执行结果进行取消、查询是否完成、获取结果等。
- FutrueTask是Futrue接口的唯一的实现类。
- FutureTask 同时实现了Runnable, Future接口。它既可以作为Runnable被线程执行,又可以作为Future得到Callable的返回值。