多线程(二)

2.Thread类及常见方法

Thread类是JVM用来管理线程的一个类,换句话说,每一个线程都有一个唯一的Thread对象与之关联。

每个执行流都需要有一个对象来描述,类似下图所示,Thread类的对象就是用来描述一个线程执行流的,JVM会将这些Thread对象组织起来,用来进行线程的调度和管理。

在这里插入图片描述

2.1 Thread常见的构造方法
在这里插入图片描述
2.2 Thread的常用属性
在这里插入图片描述

  • ID 是线程的唯一标识,不同线程不会重复。
  • name 各种调试工具会用到。
  • state 表示当前线程所处的情况。
  • priority 理论上说优先级高的线程会被先调用到。
  • daemon JVM会在一个进程的所有非后台线程结束后才会结束运行。
  • alive 线程是否存活,简单理解为 run() 方法是否运行结束了
  • interrupted 线程是否被中断,下面我们来说明
public class ThreadDemo {
    public static void main(String[] args) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    for (int i = 0; i < 10; i++) {
                        System.out.println(Thread.currentThread().getName() + "   我还活着");
                        Thread.sleep(1 * 1000);
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("我即将死去");
            }
        });
        System.out.println(Thread.currentThread().getName()
                + ": ID: " + thread.getId());
        System.out.println(Thread.currentThread().getName()
                + ": 名称: " + thread.getName());
        System.out.println(Thread.currentThread().getName()
                + ": 状态: " + thread.getState());
        System.out.println(Thread.currentThread().getName()
                + ": 优先级: " + thread.getPriority());
        System.out.println(Thread.currentThread().getName()
                + ": 后台线程: " + thread.isDaemon());
        System.out.println(Thread.currentThread().getName()
                + ": 活着: " + thread.isAlive());
        System.out.println(Thread.currentThread().getName()
                + ": 被中断: " + thread.isInterrupted());
        thread.start();
        while (thread.isAlive()) {}
        System.out.println(Thread.currentThread().getName()
                + ": 状态: " + thread.getState());
    }
}

2.3 启动一个线程 start()

之前我们了解了如何让通过覆写run()方法来创建一个线程对象,但是创建就不等于启动线程,下面我们来看如何启动线程。

  • 覆写run()方法是提供给线程要做的事情的指令清单。
  • 线程对象可以认为是李四把王五叫过来了。
  • 而调用start()方法线程才真正独立去执行了。

在这里插入图片描述
run()方法和start()方法是不同的,启动线程一定要使用run()方法。

2.4 中断一个线程

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

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

  • 通过共享的标记来通知
  • 通过interrupt()方法来中断

示例1

public class ThreadDemo {
    private static class MyRunnable implements Runnable {
        public volatile boolean isQuit = false;
        @Override
        public void run() {
            while (!isQuit) {
                System.out.println(Thread.currentThread().getName()
                        + ": 别管我,我忙着转账呢!");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName()
                    + ": 啊!险些误了大事");
        }
    }
    public static void main(String[] args) throws InterruptedException {
        MyRunnable target = new MyRunnable();
        Thread thread = new Thread(target, "李四");
        System.out.println(Thread.currentThread().getName()
                + ": 让李四开始转账。");
        thread.start();
        Thread.sleep(10 * 1000);
        System.out.println(Thread.currentThread().getName()
                + ": 老板来电话了,得赶紧通知李四对方是个骗子!");
        target.isQuit = true;
    }
}

重点说第二种方法:
1.通过Thread对象调用interrupt()方法来使该线程停止运行。
2.thead收到通知的方式有两种

  • 如果线程调用了join()/sleep()/wait()等方法挂起阻塞,则以InterruptedException异常的形式通知,清除中断标志
  • 否则只是内部的一个中断表之被设置,Thread可以通过
    Thread.interrupted()判断当前线程的中断标志位被设置,清除中断标志位
    Thead.currentThread.isInterrupted()判断指定线程的中断标志位是否被设置,不清除中断标志位

第二种方式线程收到的通知更及时,即使在sleep()也可以马上收到通知

示例2

public class ThreadDemo {
    private static class MyRunnable implements Runnable {

        @Override
        public void run() {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
                System.out.println("通过异常收到了中断情况");
            }

            for (int i = 0; i < 10; i++) {
                System.out.println(Thread.currentThread().isInterrupted());
            }
        }
    }

    public static void main(String[] args) {
        MyRunnable target = new MyRunnable();
        Thread thread = new Thread(target, "李四");
        thread.start();
        thread.interrupt();
    }
}

在这里插入图片描述
并且中断标志被清。

示例3

public class ThreadDemo {
    private static class MyRunnable implements Runnable {

        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                System.out.println(Thread.interrupted());
            }
        }
    }

    public static void main(String[] args) {
        ThreadDemo.MyRunnable target = new ThreadDemo.MyRunnable();
        Thread thread = new Thread(target, "李四");
        thread.start();
        thread.interrupt();
    }
}

在这里插入图片描述
只有一开始是true,后面都是false,因为中断标志被清了。

示例4

public class ThreadDemo6 {
    private static class MyRunnable implements Runnable {

        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                System.out.println(Thread.currentThread().isInterrupted());
            }
        }
    }

    public static void main(String[] args) {
        ThreadDemo6.MyRunnable target = new ThreadDemo6.MyRunnable();
        Thread thread = new Thread(target, "李四");
        thread.start();
        thread.interrupt();
    }
}

在这里插入图片描述
因为中断标志位没有被清除,所以全部是true

在这里插入图片描述
2.5 等待一个线程join()

有时,我们需要等待一个线程完成它的工作后,才能进行自己的下一步工作。例如,张三只有等李四转账成功,才决定是否存钱,这时我们需要一个方法明确等待线程的结束。

public class Thread1 {

    private static class MyRunnable implements Runnable {

        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                System.out.println(Thread.currentThread().getName() + ":我还在工作");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName() + ":我工作结束了");
        }
    }

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

        MyRunnable target = new MyRunnable();
        Thread thread1 = new Thread(target, "李四");
        Thread thread2 = new Thread(target, "王五");
        System.out.println("先让李四开始工作");
        thread1.start();
        thread1.join();
        System.out.println("李四工作结束了,让王五开始工作");
        thread2.start();
        thread2.join();
        System.out.println("王五工作结束了");
    }
}

试如果把两个 join 注释掉,现象会是怎么样的呢?

在这里插入图片描述

2.6 获取当前线程引用
这个方法我们当前已经比较熟悉了
在这里插入图片描述

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

2.7 休眠当前线程

有一点要记得,因为线程的调度是不可控的,所以,这个方法只能保证休眠时间是大于等于休眠时间的。

在这里插入图片描述

public class ThreadDemo {
	public static void main(String[] args) throws InterruptedException {
		System.out.println(System.currentTimeMillis());
		Thread.sleep(3 * 1000);
		System.out.println(System.currentTimeMillis());
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值