JavaEE->多线程1

发布于:2025-06-18 ⋅ 阅读:(16) ⋅ 点赞:(0)

目录

一、进程

1.什么是进程

2.内存分配 - 内存管理

3.进程中通信

4.多进程

二、线程

1.什么是线程

2.线程的优势

3.进程与线程的区别(常见面试题)

三、Java中的线程

1.如何用Java创建一个线程

2.第一个多线程程序

3.用run()方法执行线程

4.面试题

5.使用jConsole.exe查看JVM中线程的状态

6.创建线程的另一种方式(Runnable)

7.例子

8.通过创建Thread匿名内部类的方式创建线程

9.通过创建Runnable接口的匿名内部类的方式来创建一个线程

10.通过Lambda表达式创建一个线程(推荐方式)

四、多线程的优势

1.单线程

2.分别两个线程

五、Thread类及常见的方法

1.Thread的常见构造方法

2.为线程起一个名字 

3.获取线程名

4.Thread的几个常见属性

5.设置为后台进程

6.线程是否存活

7.线程中断

7.1通过共享的标记来进⾏沟通

7.2调⽤ interrupt() ⽅法来通知

1.sleep状态处理中断 

2.正常执行状态下中断线程

8.等待一个线程

六.线程的状态

1.观察线程状态

2.观察线程中所有的状态 

3.线程状态和状态转移的意义


一、进程

1.什么是进程

操作系统:
1.对下(硬件)管理更多计算机设备
2.对上(软件)为各种软件提供一个稳定运行环境

描述进程:进程控制块(PCB)
1.PID(标识系统中正在运行的进程)
2.内存指针:程序运行之前操作系统会为它分配一份有效的内存空间
3.文件描述符表(集合):程序运行起来需要访问一些文件资源,操作系统负责为程序分配资源
4.进程的状态:就绪,阻塞
5.进程的优先级:哪个进程利用CPU资源更多(不太准)
6.进程的上下文:保存上下文(读档),恢复上下文(存档)
7.进程的统计信息:统计每个进程在CPU上的运行时间和次数

进程的组织方式:
通过一个双向链表组织PCB
1.创建一个进程就是把PCB加入到链表中
2.销毁一个进程就是把PCB从链表中删除
3.查看所有的进程遍历是遍历双向链表

进程是操作系统中的一个核心单位
运行的程序在操作系统中以进程的形式存在
进程是分配资源的最小单位

2.内存分配 - 内存管理

程序运行时会分配内存空间

操作系统为了防止野指针,使用了虚拟内存来规避这个现象

通过内存管理单元(MMU)的方式来实现

3.进程中通信

目前,主流操作系统提供的进程通信机制有如下:
1.管道
2.共享内存
3.文件
4.网络
5.信号量
6.信号

4.多进程

多进程可以充分利用CPU资源区处理一些复杂的业力,从而提升业务的处理效率

串行:一个接一个的执行
并发:一会干这件事,一会干那件事
并行:一边干那件事,一边干那件事,真正意义上的同时执行

二、线程

1.什么是线程

通过多线程的方式可以提高程序处理任务的效率,创建线程的个数,根据CPU逻辑处理器的数据量来作为参考

2.线程的优势

1.线程的创建速度比进程快
2.线程的销毁速度比进程快
3.线程的CPU调度的速度比进程快

进程与进程之间,涉及的各种资源彼此之间不受影响,也就是说进程与进程之间之间是相互独立的
一个进程内线程之间是容易受到影响的

3.进程与线程的区别(常见面试题)

进程中包含线程,至少有一个主线程
进程是申请资源的最小单位
线程是CPU调度的最小单位
线程共享进程申请来的所有资源
一个线程如果崩溃了,就会影响整个进程

三、Java中的线程

1.如何用Java创建一个线程

线程:轻量级的进程,操作系统的概念

操作系统提供了一些API共程序员使用,每个操作系统提供的API都不同
API:(Application Programming Interface 应用程序编程接口)别人写好的一些函数方法,直接使用就行
Java对不同操作系统的API进行了封装
Thread类(标准库里的线程类)

2.第一个多线程程序

public class My_Thread {
    public static void main(String[] args) {
        //初始化自定义线程
        MyThread01 myThread01 = new MyThread01();
        //运行这个线程
        myThread01.start(); //启动线程,申请操作系统中的PCB,启动线程之后一个JAVA的Thread对象和 
                            //操作系统中的PCB相对应
    }
}

//自定义一个线程类,继承JDK中的Thread类
class MyThread01 extends Thread {
    @Override
    public void run() {
        while (true) {
            //可以不停的处理任务
            System.out.println("hello my thread...");
        }
    }
}

1.操作系统中的PCB
2.JAVA中的线程,Thread类的一个对象,是对PCB的一个抽象
两者不是一个概念

JAVA创建一个线程对象 ---> JVM调用系统的API ----> 创建系统中的线程(参与CPU的调度)

package demo3;

public class My_Thread02 {
    public static void main(String[] args) {
        //初始化自定义线程
        MyThread02 myThread02 = new MyThread02();
        //启动线程,创建PCB,参与CPU调度
        myThread02.start();

        //主线程中的任务
        while (true) {
            try {
                //休眠1000毫秒
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                    e.printStackTrace();
            }
            System.out.println("hello main thread...");
        }
    }
}

class MyThread02 extends Thread {
    @Override
    public void run() {
        while (true) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("hello my thread...");
        }
    }
}
//两个死循环可以同时进行,互不干扰

线程的执行顺序并没有什么规律,这个和CPU的调度有关,由于CPU调度是 "抢占式" 执行的,所以哪个线程当前占用CPU资源是不确定的

3.用run()方法执行线程

public class My_Thread02 {
    public static void main(String[] args) {
        //初始化自定义线程
        MyThread02 myThread02 = new MyThread02();
        //启动线程,创建PCB,参与CPU调度
//        myThread02.start();

        myThread02.run(); // 只是JAVA对象的一个方法而已

        //主线程中的任务
        while (true) {
            try {
                //休眠1000毫秒
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                    e.printStackTrace();
            }
            System.out.println("hello main thread...");
        }
    }
}

class MyThread02 extends Thread {
    @Override
    public void run() {
        while (true) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("hello my thread...");
        }
    }
}

因为run()方法没有结束,程序只会卡在run()方法中

4.面试题

Thread类的start()和run()方法之间的区别:
1.start()方法,真实的申请系统线程PCB,从而开启一个线程,参与CPU调度
2.run()方法,定义线程时指定线程要执行的任务,如果调用,只是Java的一个普通方法而已

5.使用jConsole.exe查看JVM中线程的状态

6.创建线程的另一种方式(Runnable)

public class My_Thread03 {
    public static void main(String[] args) {
        //创建Runnable的实例
        MyRunnable01 myRunnable01 = new MyRunnable01();
        //创建线程
        Thread thread = new Thread(myRunnable01);
        //启动线程, 创建PCB, 参与CPU调度
        thread.start();

        //主线程中的任务
        while (true) {
            try {
                //休眠1000毫秒
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                    e.printStackTrace();
            }
            System.out.println("hello main thread...");
        }
    }
}

//单独定义了线程的任务  和线程类和业务解耦 让两行代码尽量分离,以便在后面修改代码的时候相互之间的 
                     //影响最小化
class MyRunnable01 implements Runnable {
    // 实现具体的任务
    @Override
    public void run() {
        while (true) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                    e.printStackTrace();
            }
            System.out.println("hello my runnable...");
        }
    }
}

7.例子

需求:两条生产皮鞋的生产线,一双皮鞋2金币
           一条生产皮鞋的生产线,一个皮鞋5金币

三个线程,两个任务

public class My_Thread04 {
    public static void main(String[] args) {
        //实例化任务对象
        MyRunnable01 myRunnable01 = new MyRunnable01();  // 皮屑
        MyRunnable02 myRunnable02 = new MyRunnable02();  // 皮包

        //创建线程对象
        Thread thread01 = new Thread(myRunnable01);  // 皮鞋1
        Thread thread02 = new Thread(myRunnable01);  // 皮鞋2
        Thread thread03 = new Thread(myRunnable02);  // 皮包

        thread01.start();
        thread02.start();
        thread03.start();

    }
}

class MyRunnable01 implements Runnable {
    @Override
    public void run() {
        while (true) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                    e.printStackTrace();
            }
            System.out.println("生产皮鞋 , 金币 + 2....");
        }
    }
}

class MyRunnable02 implements Runnable {
    @Override
    public void run() {
        while (true) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                    e.printStackTrace();
            }
            System.out.println("生产皮包 , 金币 + 5....");
        }
    }
}

多个线程执行同一个任务就用Runnable的方式
如果中有一个线程,用Thread和Runnable都可以

8.通过创建Thread匿名内部类的方式创建线程

public class My_Thread05 {
    public static void main(String[] args) {
        Thread thread = new Thread() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("通过Thread匿名内部类的方式创建线程....");
            }
        };
        //启动线程
        thread.start();
    }
}
//通过Thread匿名内部类的方式创建线程....

9.通过创建Runnable接口的匿名内部类的方式来创建一个线程

public class My_Thread06 {
    public static void main(String[] args) {
        //匿名内部类, Runnable
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("匿名内部类, Runnable....");
            }
        });

        // 启动线程
        thread.start();
    }
}
//匿名内部类, Runnable....

10.通过Lambda表达式创建一个线程(推荐方式)

public class My_Thread07 {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> System.out.println("通过Lambda表达式创建线程...."));

        // 启动线程
        thread.start();
    }
}
//通过Lambda表达式创建线程....

四、多线程的优势

执行自增两轮10亿次

1.单线程

public class Text01 {

    //大数可以使用_分隔符
    private static long count = 10_0000_0000l;

    public static void main(String[] args) {
        //串行
        serial();
    }

    private static void serial() {
        // 记录开始时间
        long begin = System.currentTimeMillis();
        long a = 0l;
        for (int i = 0; i < count; i++) {
            a++;
        }
        long b = 0l;
        for (int i = 0; i < count; i++) {
            b++;
        }
        // 记录结束时间
        long end = System.currentTimeMillis();
        System.out.println("串行时间耗时:" + (end - begin));
    }
}
//串行时间耗时:591

2.分别两个线程

public class Text01 {

    //大数可以使用_分隔符
    private static long count = 10_0000_0000l;

    public static void main(String[] args) {
        //串行
        serial();
        //并行
        concurrency();
    }

    private static void concurrency() {
        //记录开始时间
        long begin = System.currentTimeMillis();

        //分别定义两个线程,各自执行累加操作
        //第一个线程
        Thread thread1 = new Thread(() -> {
           long a = 0l;
            for (long i = 0; i < count; i++) {
                a++;
            }
        });
        //启动thread1线程
        thread1.start();

        //第二个线程
        Thread thread2 = new Thread(() -> {
            long b = 0l;
            for (long i = 0; i < count; i++) {
                b++;
            }
        });
        //启动thread2线程
        thread2.start();

        //记录结束时间
        long end  = System.currentTimeMillis();
        System.out.println("并行执行耗时:" + (end - begin));
    }


    private static void serial() {
        // 记录开始时间
        long begin = System.currentTimeMillis();
        long a = 0l;
        for (int i = 0; i < count; i++) {
            a++;
        }
        long b = 0l;
        for (int i = 0; i < count; i++) {
            b++;
        }
        // 记录结束时间
        long end = System.currentTimeMillis();
        System.out.println("串行时间耗时:" + (end - begin));
    }
}
//串行时间耗时:572
//并行执行耗时:0  (虚假的时间)
public class Text01 {

    //大数可以使用_分隔符
    private static long count = 10_0000_0000l;

    public static void main(String[] args) {
        //串行
        serial();
        //并行
        concurrency();
    }

    private static void concurrency() {
        //记录开始时间
        long begin = System.currentTimeMillis();

        //分别定义两个线程,各自执行累加操作
        //第一个线程
        Thread thread1 = new Thread(() -> {
           long a = 0l;
            for (long i = 0; i < count; i++) {
                a++;
            }
        });
        //启动thread1线程
        thread1.start();

        //第二个线程
        Thread thread2 = new Thread(() -> {
            long b = 0l;
            for (long i = 0; i < count; i++) {
                b++;
            }
        });
        //启动thread2线程
        thread2.start();

        //等待thread1和thread2执行完成
        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
                    e.printStackTrace();
        }

        //记录结束时间
        long end  = System.currentTimeMillis();
        System.out.println("并行执行耗时:" + (end - begin));
    }


    private static void serial() {
        // 记录开始时间
        long begin = System.currentTimeMillis();
        long a = 0l;
        for (int i = 0; i < count; i++) {
            a++;
        }
        long b = 0l;
        for (int i = 0; i < count; i++) {
            b++;
        }
        // 记录结束时间
        long end = System.currentTimeMillis();
        System.out.println("串行时间耗时:" + (end - begin));
    }
}
//串行时间耗时:575
//并行执行耗时:190

通过多线程可以明显提高效率,并行耗时是串行一半多一点的时间

并不是任何时候多线程的效率都要比单线程的效率要高,但任务量很少的时候,单线程的效率可能会比多线程更高(创建线程本身也会有一定的系统开销,这个开销没有创建进程的开销大    两个线程在CPU调度也需要一定的时间)

五、Thread类及常见的方法

1.Thread的常见构造方法

可以线程起一个名字,目的是为了程序员以后方便调度程序 (默认的线程名是thread-0,N>=0)

2.为线程起一个名字 

public class Text02 {
    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            while (true) {
                System.out.println("hello thread");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        //启动t1
        t1.start();

        //指定线程名
        Thread t2 = new Thread(() -> {
            while (true) {
                System.out.println("我是一个有名字的线程...");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "我是一个线程");
        //启动t2
        t2.start();
    }
}

3.获取线程名

public class Text02 {
    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            while (true) {
                //获取线程对象
                Thread thread = Thread.currentThread();
                System.out.println(thread.getName() + " hello thread");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();;
                }
            }
        });
        //启动t1
        t1.start();

        //指定线程名
        Thread t2 = new Thread(() -> {
            while (true) {
                //获取线程对象
                Thread thread = Thread.currentThread();
                System.out.println(thread.getName() + " 我是一个有名字的线程...");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "我是一个线程");
        //启动t2
        t2.start();
    }
}

通过类 + 方法 + 线程的方式 可以明确记录某一个线程所产生的日志:

public class Text02 {
    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            while (true) {
                //获取线程对象
                Thread thread = Thread.currentThread();
                System.out.println(thread.getName() + " hello thread");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        //启动t1
//        t1.start();

        //指定线程名
        Thread t2 = new Thread(() -> {
            while (true) {
                //获取类名
                String cName = Text02.class.getName();
                //获取当前执行的方法名
                String mName = Thread.currentThread().getStackTrace()[1].getMethodName();
                //获取线程对象
                Thread thread = Thread.currentThread();
                //获取线程名
                String tName = thread.getName();

//                System.out.println(thread.getName() + " 我是一个有名字的线程...");
                System.out.println("当前类:" + cName + ", 当前方法:" + mName + ", 当前线程:" + tName);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "我是一个线程");
        //启动t2
        t2.start();
    }
}
//当前类:demo3.Text02, 当前方法:lambda$main$1, 当前线程:我是一个线程
//当前类:demo3.Text02, 当前方法:lambda$main$1, 当前线程:我是一个线程
//当前类:demo3.Text02, 当前方法:lambda$main$1, 当前线程:我是一个线程
//当前类:demo3.Text02, 当前方法:lambda$main$1, 当前线程:我是一个线程
//当前类:demo3.Text02, 当前方法:lambda$main$1, 当前线程:我是一个线程
//当前类:demo3.Text02, 当前方法:lambda$main$1, 当前线程:我是一个线程

4.Thread的几个常见属性

Thread是Java中的类 --> 创建的Thread对象 --> 调用start()方法 --> JVM调用系统API生成一个PCB --> 与Thread对象一一对应

Thread对象与PCB所处的环境不同,所以他们的生命周期也不同

public class Text03 {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    System.out.println(Thread.currentThread().getName() + ": 我还活着");
                    Thread.sleep(1 * 1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            // 退出循环

            System.out.println(Thread.currentThread().getName() + ": 我即将死去");
        });

        System.out.println(thread.getName()
                + ": ID: " + thread.getId());
        System.out.println(thread.getName()
                + ": 名称: " + thread.getName());
        System.out.println(thread.getName()
                + ": 状态: " + thread.getState());
        System.out.println(thread.getName()
                + ": 优先级: " + thread.getPriority());
        System.out.println(thread.getName()
                + ": 后台线程: " + thread.isDaemon());
        System.out.println(thread.getName()
                + ": 活着: " + thread.isAlive());
        System.out.println(thread.getName()
                + ": 被中断: " + thread.isInterrupted());

        // 启动线程,申请真正的PCB,参与CPU调度
        thread.start();
        while (thread.isAlive()) {
//            System.out.println(Thread.currentThread().getName()
//                    + ": 状态: " + thread.getState());
        }
        System.out.println(thread.getName()
                + ": 状态: " + thread.getState());
    }
}
//Thread-0: ID: 30                 系统分配
//Thread-0: 名称: Thread-0
//Thread-0: 状态: NEW              线程对象已创建
//Thread-0: 优先级: 5              不太准
//Thread-0: 后台线程: false         不是后台,即前台
//Thread-0: 活着: false            PCB已经销毁或者没有创建
//Thread-0: 被中断: false
//Thread-0: 我还活着
//Thread-0: 我还活着
//Thread-0: 我还活着
//Thread-0: 我还活着
//Thread-0: 我还活着
//Thread-0: 我还活着
//Thread-0: 我还活着
//Thread-0: 我还活着
//Thread-0: 我还活着
//Thread-0: 我还活着
//Thread-0: 我即将死去
//Thread-0: 状态: TERMINATED        线程结束

5.设置为后台进程

public class Text04 {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            while (true) {
                System.out.println("hello thread...");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        //设置为后台线程
        thread.setDaemon(true);  // 注释掉程序就不会停止
        //启动
        thread.start();
        System.out.println("线程是否存活:" + thread.isAlive());
        System.out.println("main 方法执行完成");
    }
}
//hello thread...
//线程是否存活:true
//main 方法执行完成

设置为后台线程之后,main方法执行完成之后,整个程序就退出了,子程序也就自动结束了

如果是前台线程,子程序不会受main方法的影响,会一直运行下去

创建线程时默认是前台线程 
前台线程可以阻止进程的进出
后台进程不阻止进程的退出

6.线程是否存活

public class Text05 {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                System.out.println("hello thread...");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("线程执行完成...");
        });

        System.out.println("启动之前查看线程是否存活:" + thread.isAlive());
        //启动线程
        thread.start();
        System.out.println("启动之后查看线程是否存活:" + thread.isAlive());
        //等待线程执行完成
        thread.join();
        //保证PCB已销毁
        Thread.sleep(1000);
        System.out.println("线程结束之后查看线程是否存活:" + thread.isAlive());
    }
}
//启动之前查看线程是否存活:false         还没创建PCB
//启动之后查看线程是否存活:true          PCB存在
//hello thread...
//hello thread...
//hello thread...
//hello thread...
//hello thread...
//线程执行完成...
//线程结束之后查看线程是否存活:false     PCB已销毁

7.线程中断

7.1通过共享的标记来进⾏沟通

自定义一个标志位,通过修改这个标志位,通知线程中断

中途可以通过用户的输入来发出信息

public class Text06 {
    // 自定义一个标志位
    static boolean isQuit = false;  //提为全局变量

    public static void main(String[] args) throws InterruptedException {

//        final boolean isQuit = false;

        Thread thread = new Thread(() -> {
            while (!isQuit) {         //lambda里面如果使用局部变量 触发“变量捕获”,
                                      // 如果出了main函数就会找不到  需要把变量定义为全局变量
                System.out.println("hello thread...");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            //线程退出
            System.out.println("线程退出...");
        });

        // 启动线程
        thread.start();
        // 休眠5秒
        Thread.sleep(5000);
        // 修改标志位, 相当与发送信号
        isQuit = true;
    }
}
//hello thread...
//hello thread...
//hello thread...
//hello thread...
//hello thread...
//线程退出...
7.2调⽤ interrupt() ⽅法来通知
public class Text07 {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            // 通过线程对象内部维护的中断标识,判断当前线程是否需要中断
            while (!Thread.currentThread().isInterrupted()) {
                // 线程中具体的任务是打印一句话
                System.out.println("hello thread...");

                // 线程大部分时间在sleep
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("线程退出...");
        });

        System.out.println("启动之前查看线程是否存活:" + thread.isAlive());

        // 启动线程
        thread.start();
        // 休眠一会
        Thread.sleep(1000);

        System.out.println("启动之后查看线程是否存活:" + thread.isAlive());

        // 中断线程,发出中断信号
        thread.interrupt();
        // 等待线程销毁
        Thread.sleep(1000);
        // 查看线程是否存活
        System.out.println("线程结束之后查看线程是否存活:" + thread.isAlive());
    }
}
/*
启动之前查看线程是否存活:false                                    没有启动线程
hello thread...                                                  线程启动,执行任务
hello thread...
启动之后查看线程是否存活:true                                      线程存活
hello thread...
java.lang.InterruptedException: sleep interrupted                中断线程时发现抛了个异常
	at java.base/java.lang.Thread.sleep0(Native Method)
	at java.base/java.lang.Thread.sleep(Thread.java:509)
	at demo3.Text07.lambda$main$0(Text07.java:10)
	at java.base/java.lang.Thread.run(Thread.java:1583)
hello thread...                           
线程结束之后查看线程是否存活:true                                  PCB依然存在
hello thread...                                                  任务继续执行
hello thread...
hello thread...
hello thread...
*/

当线程在sleep状态时,执行了中断操作,中断的是休眠状态的线程,就会抛出异常

1.sleep状态处理中断 
public class Text07 {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            // 通过线程对象内部维护的中断标识,判断当前线程是否需要中断
            while (!Thread.currentThread().isInterrupted()) {
                // 线程中具体的任务是打印一句话
                System.out.println("hello thread...");

                // 线程大部分时间在sleep
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    // 休眠被中断
                    System.out.println("休眠被中断...");
                    // 处理中断逻辑
                    break;
                }
            }
            System.out.println("线程退出...");
        });

        System.out.println("启动之前查看线程是否存活:" + thread.isAlive());

        // 启动线程
        thread.start();
        // 休眠一会
        Thread.sleep(1000);

        System.out.println("启动之后查看线程是否存活:" + thread.isAlive());

        // 中断线程,发出中断信号
        thread.interrupt();
        // 等待线程销毁
        Thread.sleep(1000);
        // 查看线程是否存活
        System.out.println("线程结束之后查看线程是否存活:" + thread.isAlive());
    }
}
/*
启动之前查看线程是否存活:false
hello thread...
hello thread...
启动之后查看线程是否存活:true
休眠被中断...
线程退出...
java.lang.InterruptedException: sleep interrupted
	at java.base/java.lang.Thread.sleep0(Native Method)
	at java.base/java.lang.Thread.sleep(Thread.java:509)
	at demo3.Text07.lambda$main$0(Text07.java:13)
	at java.base/java.lang.Thread.run(Thread.java:1583)
线程结束之后查看线程是否存活:false
*/
2.正常执行状态下中断线程
public class Text08 {
    public static void main(String[] args) throws InterruptedException {

        Thread thread = new Thread(() -> {
            // 通过线程对象内部维护的中断标识,判断当前线程是否需要中断
            while (!Thread.currentThread().isInterrupted()) {
                // 线程中具体的任务是打印一句话
                System.out.println("hello thread...");
            }
            System.out.println("线程已退出");
        });

        System.out.println("线程是否存活:" + thread.isAlive());
        // 启动线程
        thread.start();
        System.out.println("线程是否存活:" + thread.isAlive());
        // 中断线程,发出中断信号
        thread.interrupt();
        // 等待线程销毁
        Thread.sleep(100);
        // 查看是否存活
        System.out.println("线程是否存活:" + thread.isAlive());
    }
}
/*
线程是否存活:false
线程是否存活:true
hello thread...
hello thread...
hello thread...
hello thread...
线程已退出
线程是否存活:false
*/

调用thread.interrupt();方法时 
1.如果线程在运行状态,直接中断线程,不会报异常,符合程序预期
2.如果线程在等待状态,就会报一个终端异常,要在异常处理代码块中进行中断逻辑实现

8.等待一个线程

六.线程的状态

1.观察线程状态

public class Text01 {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            for (int i = 0; i < 10_0000_0000l; i++) {
                // 啥也不干
            }
        });
        // 启动之前看一下线程的状态
        System.out.println("启动之前:" + thread.getState());
        // 启动线程
        thread.start();
        // 启动之后线程的状态
        System.out.println("启动之后:" + thread.getState());
        // 等待线程执行完成
        thread.join();
        // 线程结束之后查看状态
        System.out.println("结束之后:" + thread.getState());
    }
}
/*
启动之前:NEW
启动之后:RUNNABLE
结束之后:TERMINATED
*/
public class Text01 {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                System.out.println("hello thread...");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        // 启动之前看一下线程的状态
        System.out.println("启动之前:" + thread.getState());
        // 启动线程
        thread.start();
        // 查看状态前等待一会
        TimeUnit.MILLISECONDS.sleep(500); //等待毫秒
        // 启动之后线程的状态
        System.out.println("启动之后:" + thread.getState());
        // 等待线程执行完成
        thread.join();
        // 线程结束之后查看状态
        System.out.println("结束之后:" + thread.getState());
    }
}
/*
启动之前:NEW
hello thread...
启动之后:TIMED_WAITING
hello thread...
hello thread...
hello thread...
hello thread...
结束之后:TERMINATED
*/

2.观察线程中所有的状态 

/**
 * 查看JDK中Thread对象的所有状态
 */

public class Text02 {
    public static void main(String[] args) {

        //线程状态 定义在一个枚举当中
        for (Thread.State state : Thread.State.values()) {
            System.out.println(state);
        }
    }
}
/*
NEW
RUNNABLE
BLOCKED
WAITING
TIMED_WAITING
TERMINATED
*/

3.线程状态和状态转移的意义


网站公告

今日签到

点亮在社区的每一天
去签到