Thread 类的基本用法

文章目录

  • 一、线程创建
    • 1.1 Thread的常见构造方法
    • 2.1 创建线程
  • 二、线程中断
    • 2.1 Thread的几个常见属性
    • 2.2 中断线程
  • 三、线程等待
  • 四、线程休眠
  • 五、获取线程实例

一、线程创建

1.1 Thread的常见构造方法

方法 说明
Thread() 创建线程对象
Thread(Runnable target) 使用Runnable对象创建线程对象
Thread(String name) 创建线程对象,并命名
Thread(Runnable target,String name) 使用Runnable对象创建线程对象,并命名

2.1 创建线程

Thread t1 = new Thread();
Thread t2 = new Thread(new MyRunnable());
Thread t3 = new Thread("这是我的名字");
Thread t4 = new Thread(new MyRunnable(), "这是我的名字");

二、线程中断

2.1 Thread的几个常见属性

属性 获取方法
ID getId()
名称 getName()
状态 getState()
优先级 getPriority()
是否后台线程 isDaemon()
是否存活 isAlive()
是否被中断 isInterrupted()
  • ID是线程的唯一标识,不同线程不会重复
  • 名称是各种调试工具用到
  • 状态表示线程当前所处的一个情况
  • 优先级高的线程理论上来说更容易被调度到
  • 关于后台线程,需要记住一点:JVM会在一个进程的所有非后台线程结束后,才会结束运行
  • 是否存活,即简单的理解,为run方法是否运行结束了

2.2 中断线程

中断线程,就是让一个线程停下来,本质上说,让一个线程终止,只有一个办法,那就是让线程的入口方法,执行完毕!

目前常见的有以下两种方式用以中断线程:

  1. 通过共享的标记来进行沟通
  2. 调用interrupt()方法来通知

第一种:需要自定义一个标志位,并且需要给该标志位加上一个volatile关键字修饰,代码如下:

package threrading;

public class ThreadDemo8 {

        //lambda表达式中访问外部的局部变量遵循 变量捕获语法规则
        //java中要求变量捕获必须是finall或者没有被修改过的变量

    public volatile boolean isQuit = false;  //设置标志位 控制循环

    public static void main(String[] args) {
        Thread t = new Thread( ()->{
            while (!isQuit){
                System.out.println("hello t");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("t 线程结束");
        });

        t.start();

        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //在主线程中修改isQuit
        isQuit=true;
    }
}

第二种: 使用 Thread.interrupted() 或者 Thread.currentThread().isInterrupted() 代替自定义标志位,代码如下:

package threrading;

public class ThreadDemo9 {
    public static void main(String[] args) {
        Thread t = new Thread(()->{
            //currentThread是获取当前线程的实例
            //此处currentThread 得到的就是t
            //isInterrupted 就是t对象里自带的一个标志位
           while (!Thread.currentThread().isInterrupted()){
               System.out.println("hello t");
               try {
                   Thread.sleep(1000);
               } catch (InterruptedException e) {
                   //报异常之后,如果需要结束循环,就需要在这下面手动加一个break;
                   e.printStackTrace();
                   break;
               }
           }
        });

        t.start(); //代码执行到这里,主线程继续执行,新线程进入run中去执行,两个进程并发执行

        /**
         * 如果slepp执行时看到这个标志位是false,sleep正常进行休眠操作
         * 如果当前标志位是true,
         * sleep无论是刚刚执行还是已经执行了一半,都会触发两件事:
         *  1.立即抛出异常
         *  2.清空标志位为false  (此后,标志位一直为false,因为主线程的t.interrupt();只被执行一次)
         */
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //把t内部的标志位 设置为true
            //  主线程并非是循环反复设置,而是只执行一次

        t.interrupt();  //这个执行完,主线程就执行完了

        /*
            interrupt的作用:
                1.设置标志位为true
                2.如果该线程正在阻塞中(比如在执行sleep)
                    此时就会把阻塞状态唤醒
                    通过抛出异常的方式让sleep立即结束
         */

            /*
            注意:
                   当sleep被唤醒的时候,sleep会自动把isInterrupted标志位自动清空(true-->false)
                为啥要sleep清空标志位呢?
                    目的就是为了让线程自身能够对于线程何时结束,有一个更明确的控制
             */

    }
}

三、线程等待

线程之间是并发执行的,操作系统对于系统的调度,是无序的,无法判定两个线程谁先执行结束,谁后执行结束!但是在实际开发过程中,有时候我们需要明确规定某一个线程要先执行完,这时候我们就需要调用线程的 join() 方法。

假设在一段代码中有一个线程 t 以及其主线程(main), t 线程启动之后,如果在main线程中调用 t.join() ,意思就是让main线程等待 t 线程先结束,再往下执行!!!

如果是 t1 线程中调用 t2.join() ,就是让 t1 线程等待 t2 线程先结束,此时 t1线程进入阻塞状态,其他线程正常调度。

package threrading;

public class ThreadDemo10 {
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(()->{
            System.out.println("hello t");
        });
        t.start();

        t.join();  //在执行时,如果t线程还没有结束,main线程就会 阻塞(Blocking) 等待。如果t已经结束,就不会阻塞,main继续执行。
        //是在main线程中,调用t.join。意思是让main线程等待t先结束,再往下执行

        //如果是t1线程中,调用t2.join。就是让t1线程等待t2先结束
            //t1线程进入阻塞,其他线程正常调度

        System.out.println("hello main");
    }
}

四、线程休眠

休眠线程,就是调用Thread.sleep()方法,这里会抛出异常。

但是值得注意的是,由于线程的调度是不可控的,所以这个方法只能保证实际休眠时间大于等于参数设置的休眠时间

五、获取线程实例

获取线程的实例非常的简单,就是调用Thread.currentThread()方法,这个在线程中断部分提及过,下面是简单的代码示例:

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

你可能感兴趣的:(JavaEE,jvm,java,开发语言,安全)