1、认识线程(thread)
1.1概念
1)线程是什么?
一个线程就是一个“执行流”,每个线程之间都可以按照一定的顺序执行自己的代码,多个线程之间“同时”执行着多段代码。
2)为什么有线程?
- 首先,由于“并发编程”逐渐成为了主流开发模式,单核cpu的发展遭遇了瓶颈,要想提高算力,就需要多核cpu,而并发编程能更充分利用多核cpu资源,而且当系统进行“IO操作”的时候,cpu会进入阻塞状态,而为了利用这段时间来提高工作效率,我们也需要并发编程。
- 其次,线程比进程更为轻量,无论是创建、销毁还是调度,线程的速度都快于进程,这使得效率大大提升。
3)进程和线程的区别
- 进程包含线程,每个进程至少有一个线程存在,即主线程
- 进程和进程之间不存在共享空间,而同一个进程的线程之间共用同一块资源
- 进程是系统分配资源的最小单位,线程是系统调度的最小单位(重要)
2、创建线程
1)继承Thread类
class MyThread extends Thread{
@Override
public void run() {
System.out.println("这是继承自Thread的类");
}
}
public class Demo25 {
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
}
}
2)实现runnable接口
class MyThread2 implements Runnable{
@Override
public void run() {
System.out.println("这是实现runnable接口");
}
}
public class Demo26 {
public static void main(String[] args) {
Thread t = new Thread(new MyThread2());
t.start();
}
}
3)匿名内部类
public class Demo27 {
public static void main(String[] args) {
Thread t = new Thread(){
@Override
public void run() {
System.out.println("这是匿名内部类实现");
}
};
t.start();
}
}
4)lambda表达式
public class Demo28 {
public static void main(String[] args) {
Thread t = new Thread(() -> {
System.out.println("这是lambda表达式实现");
});
t.start();
}
}
lambda表达式本质上是一个“匿名函数”,这样的匿名函数,主要就可以用来做为“回调函数”适用。回调函数是不需要我们手动调用的,而是在合适的时候,自动被调用。
5)基于callable(后期补充)
6)基于线程池(后期补充)
3、Thread类及常见方法
1)Thread常见构造方法
2)启动一个线程-start()
此处切记,启动线程是适用start方法,不是直接调用run方法,只有调用了start方法,后台才会真正创建出一个线程。
3)等待一个线程-join()
假设我们创建了A线程和B线程,如果A线程想让B线程先结束,就在A线程中调用B线程的join方法,让A线程在B线程结束前进入阻塞状态。
//如果A线程想让B线程先结束,则在A进程中调用B.join(),让A线程在B线程结束之前进入阻塞状态,直到B线程结束,A的阻塞状态结束
//join可以设置等待时间,防止程序“挂”掉,影响后续进程执行
//join能被interrupt唤醒
//sleep , join , wait ...产生阻塞后,都是能被interrupt唤醒,唤醒后都会自动清除标志位
public class Demo9 {
public static void main(String[] args) {
Thread B = new Thread(() -> {
for (int i = 0;i < 5;i++){
System.out.println("hello B");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println("B 结束了");
});
Thread A = new Thread(() -> {
for(int i = 0;i < 3;i++){
System.out.println("hello A");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
try {
B.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println("A 结束了");
});
A.start();
B.start();
}
}
4)线程休眠-sleep()
我们在上面的哪些代码里,我们为了让效果更为直观,都引入了Thread.sleep()这么一个代码,这个目的就是让线程进行休眠一段时间,相当于由运行状态进入阻塞等待状态,直到休眠时间到了,才继续运行,sleep中可以指定参数,表示休眠时间多少,具体内容可查看官方文档。
5)获取当前线程状态-currentThread()
目的是获得当前线程状态的引用。
4、线程状态
NEW:安排了工作,还没开始行动
RUNNABLE:已经准备开始行动了,或正在行动中
BLOCKED:进入阻塞状态,等待工作
WAITING:进入阻塞状态,等待工作
TIMED_WAITING:进入阻塞状态,等待工作
TERMINATED:工作已经完成