Java多线程(二):线程的常用方法和状态

目录

1.线程常用方法

1.1 线程终止

1.1.1 自定义标记符 

1.1.2 使用 Interrupt()

1.2 线程等待 join—李四接班

1.3 yield 让出执行权

1.4 获取当前线程

1.5 休眠当前线程 

1.5.1 使用 sleep 休眠

1.5.2 使用 TimeUnit 休眠

2.线程状态

2.1 所有的线程状态

2.2 线程状态转变


1.线程常用方法

1.1 线程终止

李四⼀旦进到工作状态,他就会按照行动指南上的步骤去进行工作,不完成是不会结束的。但有时我们需要增加⼀些机制,例如老板突然来电话了,说转账的对⽅是个骗子,需要赶紧停止转账,那张三该如何通知李四停止呢?这就涉及到我们的停止线程的方式了。

目前常见的有以下两种方式:

  1. 通过 自定义标记符 来进行中断。
  2. 调用 interrupt() 方法来中断。

1.1.1 自定义标记符 

    // 1.先声明一个标识符
    private volatile static boolean flag = true;

    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            while (flag) {
                System.out.println("正在交易......");
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("快溜~~~");
        });
        thread.start();
        Thread.sleep(3000);
        // 终止线程
        System.out.println("有内鬼,终止交易!");
        flag = false;
    }

运行结果:

1.1.2 使用 Interrupt()

        使用 Thread.interrupted() 或者 Thread.currentThread().isInterrupted() 代替自定义标志位.

使用 thread 对象的 interrupted() 方法通知线程结束: 

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            while (!Thread.interrupted()) {
                try {
                    Thread.sleep(TimeUnit.SECONDS.toMillis(1));
                    System.out.println("我正在转账");
                } catch (InterruptedException e) {
                    break;
                }
            }
            System.out.println("啊?险些误了⼤事");
        }, "⼦线程");
        t1.start();
        Thread.sleep(2200);
        System.out.println("停⽌转账有内⻤");
        t1.interrupt();
    }

运行结果:

注意interrupt() 需要配合 Thread.interrupted()Thread.currentThread().isInterrupted() 一块使用,从而实现线程终止。

isInterrupted VS interrupted:

  • interrupted:判断当前线程的中断标志位是否设置,调用后清除标志位。
  • isInterrupted:判断对象关联的线程的标志位是否设置,调用后不清除标志位。

对比代码如下: 

    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            System.out.println("终止标志位:" + Thread.currentThread().isInterrupted());
            while (!Thread.interrupted()) {
                System.out.println("正在交易.....");
            }
            System.out.println("啊?险些误了大事!");
            System.out.println("终止标志位2:" + Thread.currentThread().isInterrupted());
            System.out.println("终止标志位2:" + Thread.currentThread().isInterrupted());
            System.out.println("终止标志位2:" + Thread.currentThread().isInterrupted());
            System.out.println();
            System.out.println("终止标志位4:" + Thread.interrupted());
            System.out.println("终止标志位4:" + Thread.interrupted());
            System.out.println("终止标志位4:" + Thread.interrupted());
        });
        thread.start();
        Thread.sleep(100);

        // 终止线程
        thread.interrupt();

        System.out.println("有内鬼,终止交易!");
    }

运行结果:

停止线程的 3 种方法https://juejin.cn/post/7069920237558169613 

1.2 线程等待 join—李四接班

         有时,我们需要等待⼀个线程完成它的工作后,才能进行自己的下⼀步工作。例如,李四只有等张三下班了他才上班,这时我们需要⼀个方法明确等待线程的结束。

 

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            // 张三开始上班
            System.out.println("1.张三开始上班:" + LocalDateTime.now());
            // 张三正在上班
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 张三下班
            System.out.println("3.张三下班:" + LocalDateTime.now());
        });
        // 启动线程
        t1.start();

        // 等待线程1执行完之后再执行后面的代码
        t1.join();

        Thread t2 = new Thread(() -> {
            // 李四开始上班
            System.out.println("1.李四开始上班:" + LocalDateTime.now());
            // 李四正在上班
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 李四下班
            System.out.println("3.李四下班:" + LocalDateTime.now());
        });
        // 启动线程
        t2.start();
    }

运行结果:

1.3 yield 让出执行权

我们可以使用 yield 让出执行权,如下代码所示:

    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            // 得到当前线程
            Thread t = Thread.currentThread();
            for (int i = 0; i < 100; i++) {
                // 让出CPU执行权
                Thread.yield();
                System.out.println("执行了线程" + t.getName());
            }
        }, "张三");
        thread.start();

        new Thread(() -> {
            // 得到当前线程
            Thread t = Thread.currentThread();
            for (int i = 0; i < 100; i++) {
                System.out.println("执行了线程" + t.getName());
            }
        }, "李四").start();
    }

运行结果:

可以看到,使用 yield 时, 张三的数量远远少于李四 。

结论yield 不改变线程的状态, 但是会重新去排队,而排队之后选择谁是不确定的。

1.4 获取当前线程

 这个方法我们已经很熟悉了,下面看一个例子:

    public static void main(String[] args) {
        Thread thread = Thread.currentThread();
        System.out.println(thread.getName());
    }

运行结果:

当前线程为主线程。

1.5 休眠当前线程 

休眠线程有两种实现:

  • 使用 sleep 休眠
  • 使用 TimeUnit 休眠

1.5.1 使用 sleep 休眠

    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            try {
                Thread.sleep(60 * 1000);
            } catch (InterruptedException e) {
                System.out.println("接受到了线程终止的通知");
            }
        });
        thread.start();

        Thread.sleep(1000);
        System.out.println("终止子线程");
        thread.interrupt();
    }

 运行结果:

1.5.2 使用 TimeUnit 休眠

TimeUnit.DAYS.sleep(1);//天
TimeUnit.HOURS.sleep(1);//⼩时
TimeUnit.MINUTES.sleep(1);//分
TimeUnit.SECONDS.sleep(1);//秒
TimeUnit.MILLISECONDS.sleep(1000);//毫秒
TimeUnit.MICROSECONDS.sleep(1000);//微妙
TimeUnit.NANOSECONDS.sleep(1000);//纳秒

下面看看源码: 

 

 可以看到 TimeUnit 底层也是通过 sleep 实现的。

2.线程状态

2.1 所有的线程状态

        for (Thread.State item : Thread.State.values()) {
            System.out.println(item);
        }

可以看到总共有六种状态:

  • NEW(新建): 线程被创建,但是还未启动(start)
  • RUNNABLE(运行): 可工作的.,又可以分成正在工作中和即将开始工作
  • BLOCKED(阻塞): 如果遇到锁,线程就会变为阻塞状态,等待另一个线程释放锁
  • WAITING(等待): 无限期等待
  • TIMED_WAITING(超时等待): 有明确结束时间的等待状态
  • TERMINATED(终止): 线程结束完成

2.2 线程状态转变

 这个图看着挺复杂,下面用一个例子加以解释:

         刚把李四、王五找来,还是给他们在安排任务,没让他们行动起来,就是 NEW 状态;

        当李四、王五开始去窗口排队,等待服务,就进入到 RUNNABLE 状态。该状态并不表示已经被银行工作⼈员开始接待,排在队伍中也是属于该状态,即可被服务的状态,是否开始服务,则看调度器的调度

         当李四、王五因为⼀些事情需要去忙,例如需要填写信息、回家取证件、发呆⼀会等时,进入 BLOCKEDWATINGTIMED_WAITING 状态。

        如果李四、王五已经忙完,为 TERMINATED 状态。

观察线程状态的转换:

    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            Thread t = Thread.currentThread();
            System.out.println("线程状态2:" + t.getState());
        });
        System.out.println("线程状态1:" + thread.getState());
        thread.start();
        Thread.sleep(500);
        System.out.println("线程状态3:" + thread.getState());
    }

运行结果:

更多线程状态转换的示例https://juejin.cn/post/7065856076737937438

  • 12
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

澄白易

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值