多线程 – 线程及其创建方法
进程与线程:例如电脑上许多app,每一个app都是一个进程,而一个进程中包括很多功能(线程)任务。
单核 CPU 的发展遇到了瓶颈,要想提高算力,就需要多核 CPU。 而并发编程能更充分利用多核 CPU 资源。对于多核 CPU,并发执行多个进程,多个核心并发或并行执行多个线程,一个核心代表一个执行线程单位,一个线程内具有相应的任务。
1.进程与线程的区别与联系
-
关系上:一个进程包含一个或者多个线程;
-
空间上:不同的进程有不同的地址空间,而同一个进程中的线程共用该进程的空间;
-
隔离性:进程间不会相互影响,而同一个进程中的多个线程会相互影响;
-
单位:进程是操作系统分配资源的基本单位,线程是操作系统调度的基本单位。
-
开销:进程和线程都能解决并发编程问题,但是在创建、销毁和调度中,进程的系统开销要大于线程的系统开销。
2.java创建线程方法
总结起来一共涉及一个类两个接口,Thread类,Runnable接口和Callable接口,具体创建方法共有三种:
-
普通方式,子类继承或子类实现实现
-
直接匿名内部类
-
Lambda 表达式
📌针对“一类两口”的创建方法如下:
🎯一些具体实现:
1、Thread类,子类继承 Thread, 重写 run
class MyThread extends Thread {
@Override
public void run() {
System.out.println("Hello Thread!");
}
}
public class Thread01 {
public static void main(String[] args) {
Thread thread = new MyThread();
thread.start();
}
}
2、Thread类,使用匿名内部类继承 Thread, 重写 run
Thread thread = new Thread(){
@Override
public void run() {
System.out.println("Hello Thread!");
}
};
thread.start();
3、Thread类,lambda,alt+enter测试
4、Runnable接口,子类实现 Runnable, 重写 run
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("Hello Thread!");
}
}
public class Thread01 {
public static void main(String[] args) {
Thread thread = new Thread(new MyRunnable());
thread.start();
}
}
5、Runnable接口,使用匿名内部类实现 Runnable, 重写 run
Thread thread = new Thread(new Runnable(){
@Override
public void run() {
System.out.println("Hello Thread!");
}
});
thread.start();
6、Runnable接口,使用 lambda 表达式
Thread thread = new Thread(()->{
System.out.println("Hello Thread!");
});
thread.start();
7、Callable接口,子类实现Callable接口,重写call方法,借助FutureTask包装,放到Thread的构造方法中。
// 返回值以Integer为例
class MyCallable implements Callable<Integer> {
@Override
public Integer call() throws Exception {
return null;
}
}
public class Thread {
public static void main(String[] args) throws ExecutionException, InterruptedException {
Callable<Integer> callable = new MyCallable();
FutureTask<Integer> futureTask = new FutureTask<>(callable);
Thread threadWorkForCallableTask = new Thread(futureTask);
threadWorkForCallableTask.start();
System.out.println(futureTask.get());
}
}
8、Callable接口,匿名内部类
public static void main(String[] args) throws ExecutionException, InterruptedException {
Callable<Integer> callable = new Callable<Integer>() {
@Override
public Integer call() throws Exception {
return null;
}
};
FutureTask<Integer> futureTask = new FutureTask<>(callable);
Thread threadWorkForCallableTask = new Thread(futureTask);
threadWorkForCallableTask.start();
System.out.println(futureTask.get());
}
9、Callable接口,lambda表达式
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask<Integer> futureTask = new FutureTask<>(() -> return null);
Thread threadWorkForCallableTask = new Thread(futureTask);
threadWorkForCallableTask.start();
System.out.println(futureTask.get());
}
3.start() & run()
start方法才是启动线程,run方法是执行线程的任务。当调用start方法启动线程后,run方法也会随之被调用。如果直接调用run方法,这相当于调用一个普通方法。
🎯实例:run方法启动线程
public static void main(String[] args) {
Thread thread = new Thread(() -> System.out.println("Hello Thread!-5"));
thread.run();
System.out.println("Hello main");
}
结果:这看起来好像没什么问题。
Hello Thread!-5
Hello main
修改线程任务:
public static void main(String[] args) {
Thread thread = new Thread(() -> {
while (true) {
System.out.println("Hello Thread!-5");
}
});
thread.run();
System.out.println("Hello main");
}
📌结果:死循环执行线程thread的任务,main线程一直等待无法执行下面的打印,即如果直接调用run方法,这相当于调用一个普通方法。