文章目录
- 一、进程和线程是什么
- 二、Java.lang.Thread
- 三、Thread常用方法
- 四、线程安全(面试重点)
- 五、volatile关键字(面试重点)
- 六、线程间等待与唤醒机制(面试重点)
- 七、单例模式(面试重点)
- 八、阻塞队列
- 九、线程池
- 十、常用锁的策略
- 十一、线程工具类 java.util.concurrent
- 十二、面试问题
一、进程和线程是什么
1.1程序
1.2端口号和PID
1.3进程和线程
有进程实现并发编程为什么还要使用线程?
虽然多进程也能实现并发编程, 但是线程比进程更轻量:所以线程又叫轻量级进程;
创建线程比创建进程更快;
销毁线程比销毁进程更快;
调度线程比调度进程更快;
两者区别(面试重点)
Tset就是进程,main是主线程,此时多余的一个进程java.exe是idea自己
总结:
1.4串行、并行、并发
二、Java.lang.Thread
2.1第一个多线程代码
注意事项:
1.启动线程是start方法,不是run方法。通过start方法将线程启动以后,每个线程自动执行自己的run方法
2.Thread-0这些线程名字是默认的,可以修改
3.这四个线程同时执行,互不影响
2.2 jconsole命令
2.3创建线程的四种方法(重点)
继承Thread类
继承Thread的子类就是一个线程实体
// 定义一个Thread类,相当于一个线程的模板
class MyThread01 extends Thread {
// 重写run方法
// run方法描述的是线程要执行的具体任务
@Overridepublic
void run() {
System.out.println("hello, thread.");
}
}
/**
* 继承Thread类并重写run方法创建一个线程
* @author rose
* @created 2022-06-20
*/
public class Thread_demo01 {
public static void main(String[] args) {
// 实例化一个线程对象
MyThread01 t = new MyThread01();
// 真正的去申请系统线程,参与CPU调度
t.start();
}
}
实现Runnable接口
这个实现Runnable接口的子类,并不是真正的的线程实体,只是线程的一个核心工作任务。这是和第一种方法最大的区别
// 创建一个Runnable的实现类,并实现run方法
// Runnable主要描述的是线程的任务
class MyRunnable01 implements Runnable {
@Overridepublic void run() {
System.out.println("hello, thread.");
}
}
/**
* 通过实现Runnable接口并实现run方法
* @author rose
* @created 2022-06-20
*/
public class Thread_demo02 {
public static void main(String[] args) {
// 实例化Runnable对象
MyRunnable01 runnable01 = new MyRunnable01();
// 实例化线程对象并绑定任务
Thread t = new Thread(runnable01);
// 真正的去申请系统线程参与CPU调度
t.start();
}
}
1.创建线程任务对象
2.创建线程对象,并传入任务对象
3.调用Thread类的start方法启动线程
两种方式各自优势
1.两种方式创建线程最后都是通过Thread类的start方法启动线程
2.继承Thread类方法创建线程属于单继承,有局限性
3.实现Runnable接口的子类更加灵活,不仅实现Runnable接口,还可以继承其他类
4.调用当前线程的区别:继承Thread类,直接使用this就表示当前线程对象的引用;实现Runnable 接口, this 表示的是 MyRunnable 的引用. 需要使用 Thread.currentThread()
两种创健线程方式的不同写法
匿名内部类继承Thread类和实现Runnable接口
/**
* @author hide_on_bush
* @date 2022/7/12
*/
public class OtherMethod {
public static void main(String[] args) {
//1.匿名内部类继承Thread类
Thread thread=new Thread(){
@Override
public void run() {
System.out.println("这是匿名内部类继承Thread类");
System.out.println(Thread.currentThread().getName());
}
};
//2.匿名内部类实现Runnable接口
Thread runThread=new Thread(new Runnable() {
@Override
public void run() {
System.out.println("这是匿名内部类实现Runnable接口");
System.out.println(Thread.currentThread().getName());
}
});
thread.start();
runThread.start();
System.out.println("这是主线程"+Thread.currentThread().getName());
}
}
Lambda表达式
lambda表达式是建立在函数式接口,只有一个抽象方法!!!
//3.Lambad
Thread lambadaThread=new Thread(()-> System.out.println("这是Lambda表达式实现Runnable接口"));
实现Callable接口
- 使用线程池实现Callable接口,FutureTast是Future子类
2.4并发和串行时间对比
理论上:并发执行速度是顺序执行的一倍,所以串行耗时应该是并发的一倍
实际上:线程的创建、销毁和调用也会耗时,所以实际的时间比理论实践多一点
结论:多线程的最大好处就是调高系统处理效率
2.5 练习
正解:可能先打印1也可能先打印2,具体先调度子线程输出还是先调度主线程输出由系统决定。
至于为什么多次试验都是 21的结果:子线程位于主线程中,当t.start时主线程已经在运行,所以往往都先跑主线程才看到子线程结果
public class Thread_2533 {
public static void main(String[] args) throws InterruptedEx