Java学习总结之多线程
时间:2022年7月27日
1.什么是线程
1.1概念
一个线程就是一个”执行流",每个线程都可以按照顺序执行自己的代码,多个"线程"之间同时执行多份代码
1.2为什么要有线程
-
"并发编程"成为刚需
- 当单核CPU遇到问题,还是会采用多核CPU,那么并发编程能更充分利用多核 CPU
资源
- 当单核CPU遇到问题,还是会采用多核CPU,那么并发编程能更充分利用多核 CPU
-
进程虽然也可以实现并发编程,但是线程比进程更轻量
- 创建线程比创建进程更快
- 销毁线程比销毁进程更快
- 调度线程比调度进程更快
1.3进程和线程之间的关系
一个进程中可以有多个线程,多个线程共享进程的堆和方法区 (JDK1.8 之后的元空间)资源,但是每个线程有自己的程序计数器、虚拟机栈 (线程私有)和 本地方法栈(线程私有)
- 什么是虚拟机栈,本地方法栈
(1)虚拟机栈:每个 Java 方法在执行的同时会创建一个栈帧用于存储局部变量表、操作数栈、常量池引用等信息。从方法调用直至执行完成的过程,就对应着一个栈帧在 Java 虚拟机栈中入栈和出栈的过程。
(2)本地方法栈:和虚拟机栈所发挥的作用非常相似,区别是: 虚拟机栈为虚拟机执行 Java 方法 (也就是字节码)服务,而本地方法栈则为虚拟机使用到的 Native 方法服务。 在 HotSpot 虚拟机中和 Java 虚拟机栈合二为一
1.4Java线程和操作系统的线程之间的关系
- 线程是操作系统中的概念. 操作系统内核实现了线程这样的机制, 并且对用户层提供了一些 API 供用户使用
- Java 标准库中 Thread 类可以视为是对操作系统提供的 API 进行了进一步的抽象和封装
1.5用户线程和守护线程区别
- Java程序的进程里有几个线程:主线程,垃圾回收线程(后台线程),守护线程等,在main线程是默认的非守护线程,也就是用户线程
- 在用户线程创建线程也是用户线程
- 在守护线程下创建的子线程也是守护线程
- 关系:当没有用户线程,那么守护线程也就没存在必要了
- 区别:JVM不等待守护线程执行完退出,JVM会等待用户线程执行完退出
2.创建线程的方式
2.1方法一继承Thread类
class MyThread1 extends Thread{
@Override
public void run() {
//业务代码
Thread thread = Thread.currentThread();
System.out.println("名称:" + thread.getName());
}
}
public class ThreadDemo1 {
public static void main(String[] args) {
//获得当前的线程
Thread mainThread = Thread.currentThread();
System.out.println("名称:" + mainThread.getName());
Thread thread = new MyThread1();
//开启线程
thread.start();
}
}
2.2实现Runnable
class MyThread2 implements Runnable{
@Override
public void run() {
Thread thread = Thread.currentThread();//得到当前线程
System.out.println("名称:" + thread.getName());
}
}
public class ThreadDemo2 {
public static void main(String[] args) {
MyThread2 myThread2 = new MyThread2();
//创建线程
Thread thread = new Thread(myThread2);
//启动线程
thread.start();
}
}
2.3继承Thread类,使用匿名内部类
public class ThreadDemo4 {
public static void main(String[] args) {
Thread thread = new Thread(){
@Override
public void run() {
// 业务代码
Thread thread2 = Thread.currentThread();
System.out.println("名称" + thread2.getName());
}
};
//开始线程
thread.start();
}
}
2.4实现Runnable,使用匿名内部类
public class ThreadDemo3 {
public static void main(String[] args) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
//具体业务
Thread thread1 = Thread.currentThread();
System.out.println("名称:" + thread1.getName());
}
});
//开启线程
thread.start();
}
}
2.5使用lambda 表达式创建 Runnable 子类对象
public class ThreadDemo5 {
public static void main(String[] args) {
//创建线程
Thread thread = new Thread(()->{
//业务代码
Thread thread3 = Thread.currentThread();
System.out.println("名称" + thread3.getName());
});
//启动线程
thread.start();
}
}
2.6带有返回值的callable
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class ThreadDemo6 {
public static void main(String[] args)throws ExecutionException, InterruptedException {
// 创建 Callable 实例
MyCallable callable = new MyCallable();
// 用于接收 Callable 结果的对象
FutureTask<Integer> futureTask = new FutureTask<Integer>(callable);
// 创建新线程
Thread thread = new Thread(futureTask);
// 启动线程
thread.start();
// 接收新线程执行的结果
int result = futureTask.get();
System.out.println(Thread.currentThread().getName() +
"——新线程返回的结果为:" + result);
}
}
/**
* Callable<V> 泛型里面可以是任意数据类型
*/
class MyCallable implements Callable<Integer> {
@Override
public Integer call() throws Exception {
// 生成随机数:0-9
int randomNum = new Random().nextInt(10);
System.out.println(Thread.currentThread().getName() +
"——随机数:" + randomNum);
return randomNum;
}
}