Java多线程
多线程基础
操作系统:Windows、macOS、Linux
CPU执行代码都是一条一条顺序执行的,但是,即使是单核的CPU,也可以同时执行多任务。
例如,假设我们有语文、数学、英语3门作业要做,每个作业需要30分钟。我们把这3门作业看成是3个任务,可以做1分钟语文作业,再做1分钟数学作业,再做1分钟英语作业。
对于CPU来说,当某个线程获取了CPU时间片的时候,这个线程就会执行。
- 进程
在计算机中,我们把一个任务称为一个进程,浏览器就是一个进程,视频播放器是另一个进程。
- 线程
某些进程内部还需要同时执行多个子任务。例如,我们在使用Word时,Word可以让我们一边打字,一边进行拼写检查,同时还会实时保存。
- 进程VS线程
一个进程可以包含一个或多个线程,但至少会有一个线程。
创建新线程
Java程序启动的时候,实际上是启动了一个JVM进程,然后,JVM启动主线程来执行main()方法,在main()方法中又可以启动其他线程。
创建并启动一个线程。需要实例化一个Thread实例,然后调用它的的start()方法。
public class MainTest{
public static void main(String[] args){
Thread t = new Thread();
t.start();//启动新线程
}
}
方法一: 继承Thread类,然后重写run()方法
public class MainTest{
public static void main(String[] args){
Thread t = new MyThread();
t.start();
}
static class MyThread extends Thread{
public void run(){
sout("start new thread");
}
}
}
方法二: 实现Runnable接口,然后重写run()方法
public class MainTest{
public static void main(String[] args){
Thread t2 = new Thread(new MyRunnable());
t2.start();
}
static class MyRunnable implements Runnable{
@Override
public void run() {
System.out.println("myThread2启动!");
}
}
}
方法三: Java8引入了lambda表达式,可以进一步简写:
public class Main {
public static void main(String[] args) {
Thread t = new Thread(() -> {
System.out.println("start new thread!");
});
t.start(); // 启动新线程
}
}
其实,还有一个方法也可以:
//本方法类似于lambda表达式
Thread t4 = new Thread(){
public void run(){
System.out.println("t4线程启动!");
}
};
t4.start();
**线程休眠:**sleep()方法可以使得线程休眠。
public static native void sleep(long millis) throws InterruptedException;
Thread t3 = new Thread(()->{
try {
Thread.sleep(1000);//1000毫秒
} catch (InterruptedException e) {
System.out.println("Thread...end");
}
System.out.println("lambda表达式多线程!");
});
t3.start();
try {
Thread.sleep(10);//10毫秒
} catch (InterruptedException e) {
System.out.println("main...end");
}
Thread t4 = new Thread(){
public void run(){
System.out.println("t4线程启动!");
}
};
t4.start();
结果是:t4线程启动!
lambda表达式多线程!
线程的状态
- New:新创建的线程,尚未执行
- Runnable:运行中的线程,正在执行run()方法
- Blocked:运行中的线程,因为某些操作被阻塞而挂起
- Waiting:运行中的线程,因为某些操作在等待;
- Timed Waiting:运行中的线程,因为执行sleep()方法正在计时等待
- Terminated:线程已终止,因为run()方法执行完毕
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YhBOXJIc-1622087125647)(Java多线程.assets/image-20210520190208751.png)]
线程启动后(start)可以在四个状态中切换,最后变成Terminated状态,线程终止。
线程终止的原因:
- 正常终止:run()方法执行到return语句。
- 意外终止:未捕获异常而终止。
- 强制终止:stop()方法(不建议)
public class Main {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
try {
t2.sleep(10);//10毫秒
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("t1启动");
});
Thread t2 = new Thread(() -> {
try {
t2.sleep(1000);//10毫秒
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("t2启动");
});
System.out.println("start");
t1.start();
t2.start();
t2.join();
t.join();//t线程加入后,其他线程会等待t结束后再启动。
System.out.println("end");
}
}
中断线程
如果线程需要执行一个长时间任务,就可能需要能中断线程。中断线程就是其他线程给该线程发一个信号,该线程收到信号后结束执行run()
方法,使得自身线程能立刻结束运行。
public class Main {
public static void main(String[] args) throws InterruptedException {
Thread t = new MyThread();
t.start();
Thread.sleep(1); // 暂停1毫秒
t.interrupt(); // 中断t线程
t.join(); // 等待t线程结束
System.out.println("end");
}
}
class MyThread extends Thread {
public void run() {
int n = 0;
while (! isInterrupted()) {
n ++;
System.out.println(n + " hello!");
}
}
}
sleep()
方法是Thread类里面的,主要的意义就是让当前线程停止执行,让出cpu给其他的线程,但是不会释放对象锁资源以及监控的状态,当指定的时间到了之后又会自动恢复运行状态。
wait()
方法是Object类里面的,主要的意义就是让线程放弃当前的对象的锁,进入等待此对象的等待锁定池,只有针对此对象调动notify方法后本线程才能够进入对象锁定池准备获取对象锁进入运行状态。
t.start()
开启了新的线程,这个时候两个线程同时存在,main
和t
线程谁获得cpu时间片的概率是相同的。这个时候main
方法暂停1毫秒保证了cpu可以让t方法在中断前先执行从而输出1+“hello”。然后t
线程中断,中断以后便不会再输出n+“hello”,这个时候,然后cpu给main方法执行join再让t方法完全运行完,或者给到t方法直接运行完,最后就输出end
三线程的Interrupt
public class Main {
public static void main(String[] args) throws InterruptedException {
Thread t = new MyThread();
t.start();
Thread.sleep(1000);
t.interrupt(); // 中断t线程
t.join(); // 等待t线程结束
System.out.println("end");
}
}
class MyThread extends Thread {
public void run() {
Thread hello = new HelloThread();
hello.start(); // 启动hello线程
try {
hello.join(); // 等待hello线程结束
} catch (InterruptedException e) {
System.out.println("interrupted!");
}
hello.interrupt()