创建线程的四种方式
一、继承Thread类
- 写一个类ThreadDemo1继承Thread线程类
- 重写Thread类中run()方法
- 多态的方式new出一个ThreadDemo1类的对象指向Thread类
- 调用父类的start()方法,ThreadDemo1类中继承了父类的start()方法
class ThreadDemo1 extends Thread {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
//Thread.currentThread().getName()获取当前线程类的名字
//线程名默认从Thread-0依次递增
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
public class ThreadTest {
public static void main(String[] args) {
Thread thread = new ThreadDemo1();
thread.start();
}
}
运行结果
二、实现Runnable接口
-
写一个类ThreadDemo2实现Runnable接口
-
重写Runnable接口中run()方法
-
new一个ThreadDemo2的对象
-
调用Thread类的有参构造方法,此时需要传入一个Runnable类型的参数,也就是我们的ThreadDemo2对象
或者使用匿名子类的方式new出一个Runnable接口的子类对象
另外一种方式是lambda的方式,这两种方式不先过多介绍
-
调用Thread类的start()方法启动线程
class ThreadDemo2 implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
//Thread.currentThread().getName()获取当前线程类的名字
//线程名默认从Thread-0依次递增
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
public class ThreadTest {
public static void main(String[] args) {
ThreadDemo2 threadDemo2 = new ThreadDemo2();
Thread thread1 = new Thread(threadDemo2);
thread1.start();
}
}
运行结果
三、实现Callable接口的方式
这种方式相较于实现Runnable接口的方式更为灵活,可以抛出异常,还有可以得到线程的执行结果
- 写一个类ThreadDemo3实现Callable接口此时Callable接口有个泛型,也就是其中call()方法的返回值类型
- 重写Callable接口中call()方法,此方法可以抛出异常
- new一个ThreadDemo3的对象
- 借助FutureTask类来获取线程的执行结果,调用FutureTask类的有参构造方法,此时需要传入一个Callable类型的参数
或者使用匿名子类的方式new出一个Callable接口的子类对象
另外一种方式是lambda的方式,这两种方式也不先过多介绍
-
调用Thread类的有参构造方法,此时需要传入一个Runnable类型的参数,而FutureTask又实现了RunnableFuture,RunnableFuture继承了Runnable
public class FutureTask implements RunnableFuture
-
调用Thread类的start()方法启动线程
class ThreadDemo3 implements Callable<Integer> {
@Override
public Integer call() throws Exception {
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum = sum + i;
}
System.out.println(Thread.currentThread().getName() + ":" + sum);
return sum;
}
}
public class ThreadTest {
public static void main(String[] args) {
ThreadDemo3 threadDemo3 = new ThreadDemo3();
FutureTask<Integer> futureTask = new FutureTask<>(threadDemo3);
Thread thread3 = new Thread(futureTask);
thread3.start();
Integer sum = null;
try {
//get方法是阻塞方法,一个一个获取执行结果,直到结束
sum = futureTask.get();
//重载的方法,可以指定获取线程执行结果的时间,这个时间内获取不到结果,不会阻塞,直接获取下一个结果
//sum = futureTask.get(1000, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
System.out.println(sum);
}
}
运行结果
四、线程池管理,执行线程任务
为了方便演示,直接用Executors调用静态方法的方式执行线程任务
4.1 线程池执行Runnable任务打印10个随机数
- 创建一个两个线程的固定长度的线程池
- 创建ThreadDemo4实现Runnable接口
- 重写run()方法
- 调用线程池的execute()方法传入一个Runnable类型的参数执行
class ThreadDemo4 implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + ":" + (int) (+Math.random() * 100));
}
}
}
public class ThreadTest {
public static void main(String[] args) {
//创建固定长度的线程池
ExecutorService executorService = Executors.newFixedThreadPool(2);
ThreadDemo4 threadDemo4 = new ThreadDemo4();
executorService.execute(threadDemo4);
//关闭线程池
executorService.shutdown();
}
}
运行结果
4.2 线程池执行Callable任务获取1-100的和
- 创建两个线程的固定长度的线程池
- 创建ThreadDemo5实现Callable接口
- 重写call()方法
- 调用线程池的submit()方法传入一个Callable类型的参数执行
- 创建5个线程并行执行任务
- 借助FutureTask类来获取线程的执行结果
class ThreadDemo5 implements Callable<Integer> {
@Override
public Integer call() throws Exception {
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum = sum + i;
}
System.out.println(Thread.currentThread().getName() + ":" + sum);
return sum;
}
}
public class ThreadTest {
public static void main(String[] args) {
List<Future<Integer>> tasks = new ArrayList<>();
for (int i = 0; i < 5; i++) {
//执行5个线程任务
Future<Integer> future = executorService.submit(new ThreadDemo5());
tasks.add(future);
}
//遍历线程执行的结果
for (Future<Integer> task : tasks) {
Integer result = null;
try {
result = task.get();
System.out.println(result);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} finally {
executorService.shutdown();
}
}
}
}
运行结果