Thread 类及常见方法

2.0 Thread类是什么?

答:Thread 类是线程的描述类,每个线程都有一个 Thread 对象与之关联。

即:

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

2.1 Thread的常见构造方法

方法 说明
Thread() 创建线程对对象
Thread(Runnable target) 使用 Runnable 对象创建线程对象
Thread(String name) 创建线程对象并命名
Thread(Runnable target , String name) 使用 Runnable 对象创建线程对象并命名
public class ThreadName {
    private static class MyThread extends Thread {

        public MyThread(String name) {
            super(name);
        }

        public MyThread() {

        }

        @Override
        public void run() {
            while (true) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    public static void main(String[] args) {
        Thread t1 = new MyThread();
        Thread t2 = new MyThread("我是AAA");
        Thread t3 = new Thread(new MyThread());
        Thread t4 = new Thread(new MyThread(), "我是BBB");

        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}

用jconsole观察:
在这里插入图片描述

2.2 Thread的常见属性

属性 获取方法 补充
ID getId() 线程的唯一标识,不同线程ID不会重复
名称 getName() 在调试工具中会用到
状态 getState() 表示线程当前状态
优先级 getPriority() 优先级高的线程理论上更容易被调度
是否后台线程 isDaemon() JVM会在一个进程的所有非后台进程结束后,才结束运行
是否存活 isAlive() run方法是否运行结束
是否中断 isInterrupted() 线程是否中断
public class ThreadFields {
    private static class MyRunnable implements Runnable {
        @Override
        public void run() {
            Thread current = Thread.currentThread();
            System.out.println(current.getId());
            System.out.println(current.getName());
            System.out.println(current.getPriority());
            System.out.println(current.getState());
            System.out.println(current.isAlive());
            /*
            不能用this 此时this指的是Runnable对象 不是Thread对象
            System.out.println(this.isInterrupted());
            System.out.println(this.isDaemon());
             */
        }
    }
    private static class MyThread extends Thread {
        @Override
        public void run() {
            Thread current = Thread.currentThread();
            System.out.println(current.getId());
            System.out.println(current.getName());
            System.out.println(current.getPriority());
            System.out.println(current.getState());
            System.out.println(current.isAlive());
            //可以用this
            System.out.println(this.isInterrupted());
            System.out.println(this.isDaemon());
        }
    }

    public static void main(String[] args) {
       new MyThread().start();
    }
}

运行结果:
在这里插入图片描述

2.3 start()—启动一个线程

注意:

  • 线程对象被创建出来并不意味着线程就开始运行。
  • 启动线程必须调用start()。
  • run方法和start()方法不同。

假设:只调用run(),不调用start(),结果会是什么?

public class StartOrRun {
    private static class MyThread extends Thread {
        @Override
        public void run() {
            while (true) {
                System.out.println("MyThread");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    public static void main(String[] args) throws InterruptedException {
        Thread t = new MyThread();
        t.run();
        /* 只执行 MyThread 不执行 main
           不要调用 run
        */
        while (true) {
            System.out.println("main");
            Thread.sleep(1000);
        }
    }
}

运行结果:只输出 MyThread 不输出mian,根本达不到多线程应有的效果。所以,线程启动一定要调用start()
在这里插入图片描述

2.4 线程中断

2.4.1 通过共享标记

注意:这种方法有延迟

import javafx.scene.layout.Priority;
import javax.swing.plaf.nimbus.State;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;

public class StopThread {
    private static class Worker extends Thread {
        private volatile boolean quit = false; 
        //自定义共享标记

        Worker() {
            super("李四");
        }

        public void setQuit(boolean quit) {
            this.quit = quit;
        }

        @Override
        public void run() {
            while (!quit) {
                System.out.println(this.getName() + ": 我正在转账,别烦我");
                try {
                    //结果1
                    Thread.sleep(3000);
                    //结果2  //Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            System.out.println(this.getName() + ": 对方是骗子,我不转账了");
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Worker worker = new Worker();
        worker.start();
        System.out.println("我是张三,正在等李四转账");
        Thread.sleep(10 * 1000);
        System.out.println("打听到对方是骗子,通知李四停止转账");
        worker.setQuit(true);
        System.out.println("通知李四完毕");
        worker.join();
        System.out.println("李四停止转账");
    }
}

运行结果1:因为10不能整除3,所以有延迟(李四不能立刻做出反应)。
在这里插入图片描述

运行结果2:因为10/5可以整除,故李四立马做出反应。
在这里插入图片描述

2.4.2 调用interrupt()方法

  • 调用Thread对象的 Interrupt() 方法,会将对象的 interrupt status 置为 true,时间以型的中断。
  • 对于Thread对象关联的线程来说,有两种途径获取该信息:
  1. 如果当前线程正在 sleep/wait ,会以 InterruptedException 的形式通知。
  2. 否则,需要自行去判断对象中的 interrupt status 。
    2.1 调用对象的 isInterrupted() 方法 —— 判断该对象的 interrupt status 。
    2.2调用 Thread.interrupted() 方法 —— 判断的是当前线程对象的 interrupt status 。相当于Thread.currentThread().isInterrupted();
public class StopThread2 {
    private static class Worker extends Thread {
        Worker() {
            super("李四");
        }

        @Override
        public void run() {
            while (!this.isInterrupted()) {
                System.out.println(this.getName() + ": 我正在转账,别烦我");
                try {
                    Thread.sleep(50 * 1000);
                } catch (InterruptedException e) {
                    System.out.println("我从睡梦中惊醒");
                    break;
                }
            }
            System.out.println(this.getName() + ": 对方是骗子,我不转账了");
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Worker worker = new Worker();
        worker.start();
        System.out.println("我是张三,正在等李四转账");
        Thread.sleep(10 * 1000);
        System.out.println("打听到对方是骗子,通知李四停止转账");
        worker.interrupt();
        System.out.println("通知李四完毕");
        worker.join();
        System.out.println("李四停止转账");
    }
}

运行结果:张三只会等待10s,立即通知李四(调用 interrupt 方法),李四立刻做出响应(无延迟)。
在这里插入图片描述

2.4.3 interrupt()、interrupted()、isInterrupted()

方法 说明
public void interrupt() 中断对象关联的线程,如果线程正在阻塞,则以异常方式通知,否则设置标志位
public static boolean interrupted() 判断当前线程的中断标志位是否设置,调用后清除标志位
public boolean isInterrupted() 判断对象关联的线程的标志位是否设置,调用后不清除标志位
  • interrupt()
    在这里插入图片描述
    注意:如果是从catch (InterruptedException e) { System.out.println(this.isInterrupted()); System.out.println("我从睡梦中惊醒"); break; }分支跳出的,this.isInterrupted()依然打印的是false。

  • interrupted()
    在这里插入图片描述

  • isInterrupted()
    在这里插入图片描述

测试:

public class StopThread3 {
    private static class Worker extends Thread {
        Worker() {
            super("李四");
        }

        @Override
        public void run() {
            while (true) {
                //第一次测试
                System.out.println(Thread.interrupted()); //一次false 后全是true
                //第二次测试
                //System.out.println(this.isInterrupted()); //一直是true
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Worker worker = new Worker();
        worker.start();
        worker.interrupt(); //中断
    }
}

第一次运行结果:调用 Thread.interrupted() ,第一次输出 true ,后一直输出 false 。
在这里插入图片描述

第二次运行结果:调用 this.isInterrupted() ,一直输出 true 。

在这里插入图片描述

小结

  1. InterruptedException 被抛出,则interrupt status 被重置(=false)
  2. Thread.interrupted() 首次返回真正的线程状态,然后 interrupt status = false
  3. this.isInterrupted() 不会重置

测试:

public class InterruptThread {
    private static class MyThread1 extends Thread {
        @Override
        public void run() {
            while (true) {
                try {
                    Thread.sleep(10_000_000);
                } catch (InterruptedException e) {
                    // 通过异常的方式通知中断 我收到了中断通知 
                    System.out.println(isInterrupted()); //false
                    break;
                }
            }
            System.out.println("退出");
        }
    }

    private static class MyThread2 extends Thread {
        @Override
        public void run() {
            while (!isInterrupted()) {
            }
            // 通过判断中断状态退出,状态不会被重置
            System.out.println(isInterrupted()); //true
            System.out.println("退出");
        }
    }

    private static class MyThread3 extends Thread {
        @Override
        public void run() {
            while (!Thread.interrupted()) {
            }
            // 通过判断中断状态退出,状态被重置
            System.out.println(isInterrupted()); //false
            System.out.println("退出");
        }
    }

    public static void main(String[] args) {
        MyThread1 t1 = new MyThread1();
        t1.start();
        t1.interrupt();
        MyThread2 t2 = new MyThread2();
        t2.start();
        t2.interrupt();
        MyThread3 t3 = new MyThread3();
        t3.start();
        t3.interrupt();
    }
}

运行结果:
在这里插入图片描述

2.5 join()—等待一个线程

方法 说明
public void join() 等待线程结束
public void join(long millis) 等待线程结束,最多等待 millis 毫秒
public void join(long millis, int nanos) 同理,但精度更高

2.6 获取当前线程引用

方法 说明
public static Thread currentThread() 返回当前线程对象的引用

2.7 线程休眠

注意:因为线程的调度是不可控的,所以,这个方法只能保证线程休眠时间是大于等于休眠时间的

方法 说明
public static void sleep(long millis) throws InterruptedException 休眠当前线程 millis 毫秒
public static void sleep(long millis, int nanos) throws InterruptedException 同理,但休眠的时间精确度更高

2.8 补充

java中的内存区域

  栈             每个线程都有自己独立的栈空间
                 栈里的数据不共享
                 
  堆             大家共享的是同一个堆(包括堆里的常量池)和方法区
  方法区          堆和方法区中的数据是共享的
发布了70 篇原创文章 · 获赞 3 · 访问量 1232

猜你喜欢

转载自blog.csdn.net/qq_43361209/article/details/104105959