Java——》创建线程的方式
推荐链接:
总结——》【Java】
总结——》【Mysql】
总结——》【Redis】
总结——》【Kafka】
总结——》【Spring】
总结——》【SpringBoot】
总结——》【MyBatis、MyBatis-Plus】
总结——》【Linux】
总结——》【MongoDB】
总结——》【Elasticsearch】
Java——》创建线程的方式
Java中的线程本质上就是一个
Thread对象
。创建线程常用方式:
- 继承Thread类,重写run方法
- 实现Runnable接口
- 实现Callable接口
- 线程池
1. 继承Thread类,重写run方法
1.1 步骤
- 创建Thread类的子类
- 重写run()方法
- 创建线程对象
- 调用start()方法,启动线程
1.2 示例
package org.example;
public class CreateThreadForThread {
public static void main(String[] args) {
System.out.println("main方法执行开始...");
// Java中的线程本质上就是一个Thread对象
Thread t1 = new MyThread();
/*
start()方法:
1. 启动一个新的线程
2. 线程不能启动多次,否则报异常
3. 实际下真正开启线程的是CPU,当CPU空闲或分配到此任务的时候,就会创建一个新的线程,然后执行run()方法中的代码
*/
t1.start();
// 如果要创建多个线程,需要创建多个Thread对象
Thread t2 = new MyThread();
t2.start();
Thread t3 = new MyThread();
// 显示的调用Thread的run()方法,并没有开启新的线程
t3.run();
for (int i = 0; i < 100; i++) {
System.out.println("main方法的循环..." + i);
}
System.out.println("main方法执行结束...");
}
}
/**
* 继承Thread类,重写run方法
*/
class MyThread extends Thread{
@Override
public void run() {
System.out.println("子线程执行开始....");
for(int i = 0 ; i < 10 ; i ++){
System.out.println("子线程的循环:"+i);
}
System.out.println("子线程执行结束....");
}
}
1.3 注意
- 启动线程是使用start()方法而不是run()方法
- 调用run()方法,当前线程直接执行run()方法中的业务逻辑
- 线程不能启动多次
- 如果要创建多个线程,需要创建多个Thread对象
2. 实现Runnable接口,重写run方法
2.1 步骤
- 创建Runable的实现类
- 重写run方法
- 创建Runable实例对象(通过实现类来实现)
- 创建Thread对象,并把第3步的Runable实现作为Thread构造方法的参数
- 调用start方法,启动线程
2.2 示例
package org.example;
/**
* 创建线程对象:
* 方式1:通过Runable实现接口
* 方式2:通过Runable匿名内部类
* 方式3:通过lambda表达式
*/
public class CreateThreadForRunnable {
public static void main(String[] args) {
System.out.println("main方法执行开始...");
MyRunnable myRunnable = new MyRunnable();
// 方式1:创建Thread对象的时候传递了一个Runable接口实现
Thread t1 = new Thread(myRunnable);
// 启动线程
t1.start();
// 方式2:创建Thread对象的时候传递了一个Runable匿名内部类
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("匿名内部类的循环:" + i);
}
}
});
t2.start();
// 方式3:创建Thread对象的时候传递了一个lambda表达式
Thread t3 = new Thread(() -> {
for (int i = 0; i < 100; i++) {
System.out.println("lambda的循环:" + i);
}
});
t3.start();
for (int i = 0; i < 100; i++) {
System.out.println("main方法的循环..." + i);
}
System.out.println("main方法执行结束...");
}
}
/**
* 实现Runnable接口,重写run方法
*/
class MyRunnable implements Runnable{
@Override
public void run() {
System.out.println("子线程执行开始....");
for (int i = 0; i < 100; i++) {
System.out.println("子线程的循环:"+i);
}
System.out.println("子线程执行结束....");
}
}
2.3 优点
- 可以避免Java单继承带来的局限性
- 适合多个相同的程序代码处理同一个资源的情况,把线程同程序的代码和数据有效的分离,较好的体现了面向对象的设计思想
3. 实现Callable接口,重写call方法,配合FutureTask
前面介绍的两种创建线程的方式都是重写run()方法,而且run()方法是没有返回结果的,也就是main方法是不知道开启的线程什么时候开始执行,什么时候结束执行,也获取不到对应的返回结果。而且run()方法也不能把可能产生的异常抛出。
在
JDK1.5之后
,推出了通过实现Callable接口的方式来创建新的线程,这种方式可以获取对应的返回结果。
3.1 步骤
- 创建Callable的实现类
- 重写call()方法
- 创建Callable实例对象(通过实现类来实现)
- 创建FutureTask实例对象,传入Callable实例对象
- 创建Thread实例对象,传入FutureTask实例对象作为Thread构造方法的参数
- 调用start方法,启动线程
3.2 示例
package org.example;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class CreateThreadForCallable {
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("main方法执行开始...");
//1. 创建MyCallable
Callable<Integer> myCallable = new MyCallable();
//2. 创建FutureTask,传入Callable
FutureTask<Integer> futureTask = new FutureTask<Integer>(myCallable);
//3. 创建Thread线程, futureTask本质上是Runable接口的实现
Thread t1 = new Thread(futureTask);
//4. 启动线程,本质上是执行Runable中的run()方法,只是run()方法中调用了call()方法
t1.start();
//5. 做一些操作
//6. 线程执行完成后返回的结果
Integer count = futureTask.get();
System.out.println("总和为:" + count);
System.out.println("main方法执行结束...");
}
}
/**
* 创建Callable的实现类
* 指定Callable的泛型,这个泛型是返回结果的类型
*/
class MyCallable implements Callable<Integer> {
@Override
public Integer call() throws Exception {
System.out.println("子线程执行开始....");
int count = 0;
for (int i = 0; i < 100; i++) {
count += i;
}
System.out.println("子线程执行结束....");
return count;
}
}
3.3 底层实现
其实Callable接口底层的实现就是**对Runable接口实现的封装**,线程启动后执行的也是Runable接口实现中的run()方法,只是在run()方法中有调用call()方法。
3.4 Future对象
运行Callable任务可以拿到一个Future对象,表示**异步计算的结果**。它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。通过Future对象可以了解任务执行情况,可取消任务的执行,还可获取执行结果。
3.5 实现Runnable接口和实现Callable接口的区别
区别 | 实现Runnable接口 | 实现Callable接口 |
---|---|---|
版本 | JDK1.1之后 | JDK1.5之后 |
规定方法 | run() | call() |
返回值 | 无 | 有,Future.get() |
抛出异常 | 不可以 | 可以 |
加入线程池运行 | ExecutorService.execute() | ExecutorService.submit() |
4. 基于线程池创建线程
追其底层,其实只有一种,实现Runnble
package org.example;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ExecutorServiceTest {
public static void main(String[] args) {
ExecutorService service = Executors.newCachedThreadPool();
service.execute(() -> {
System.out.println("Hello ThreadPool");
});
}
}
5. 总结
package org.example;
import java.util.concurrent.*;
public class CreateThread {
public synchronized void m1() {
System.out.println(Thread.currentThread().getName() + " m1 ");
}
static class MyThread extends Thread {
@Override
public void run() {
System.out.println("Hello MyThread!");
}
}
static class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("Hello MyRunnable!");
}
}
// 需要指定Callable的泛型,这个泛型是返回结果的类型
static class MyCallable implements Callable<String> {
@Override
public String call() throws Exception {
System.out.println("Hello MyCallable");
return "success";
}
}
public static void main(String[] args) throws Exception {
// 第1种:继承Thread类,重写run方法
new MyThread().start();
// 第2种:实现Runnable接口,重写run方法
new Thread(new MyRunnable()).start();// 本质是创建Thread对象的时候传递了一个Runable接口实现
// 第3种:匿名内部类,重写run方法
new Thread(new Runnable(){
@Override
public void run() {
System.out.println("Hello Runnable!");
}
}).start();
// 第4种:lamda表达式
new Thread(() -> {
System.out.println("Hello Lambda!");
}).start();
// 第5种:实现Callable接口,重写call方法(运行 + 返回值)
FutureTask<String> task = new FutureTask<>(new MyCallable());// FutureTask 本质上是 Runable 接口的实现
Thread t = new Thread(task);
t.start();// 本质还是执行 Runable中的run方法,只是 run方法调用了call方法
System.out.println(task.get());// 获取线程执行完成后返回的结果
ExecutorService service = Executors.newCachedThreadPool();
// 第6种:线程池,无返回值
service.execute(() -> {
System.out.println("Hello ThreadPool");
});
// 第7种:线程池,有返回值
Future<String> f = service.submit(new MyCallable());
String s = f.get();
System.out.println(s);
service.shutdown();
CreateThread tt = new CreateThread();
//1.8之前的写法
new Thread(new Runnable() {
@Override
public void run() {
tt.m1();
}
}).start();
//1.8之后的写法:默认线程名称
new Thread(()->tt.m1()).start();
new Thread(tt::m1).start();
//1.8之后的写法:自定义线程名称
new Thread(()->tt.m1(), "t1").start();
new Thread(tt::m1, "t1").start();
}
}
原文地址:https://blog.csdn.net/weixin_43453386/article/details/143627763
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!