Thread类的基本用法

目录

线程创建

线程创建

1.继承Thread类,重写run

2.实现Runnable接口,重写run

3.匿名内部类创建Thread子类对象

4.匿名内部类创建Runnable子类对象

5.lambda表达式创建Runnable子类对象

Thread常见属性

start和run

线程中断

线程等待(join)

线程休眠

线程状态

1.NEW

2.TERMINATED

3.RUNNABLE

4.BLOCKED

5.TIMED_WAITING

6.waiting


线程创建

线程创建

1.继承Thread类,重写run
//继承Thread,创建线程类
class MyThread extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 3; i++) {
            try {
                System.out.println("hello Thread");
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}
public class D1 {
    public static void main(String[] args) throws InterruptedException {
        //创建MyThread类的实例
        MyThread thread = new MyThread();
        //调用start方法创建线程
        thread.start();
        for (int i = 0; i < 3; i++) {
            System.out.println("hello main");
            Thread.sleep(1000);
        }
    }
}
2.实现Runnable接口,重写run
//实现Runnable接口
class MyRunnable implements Runnable{
    @Override
    public void run() {
        //描述了线程要完成的逻辑
        for (int i = 0; i < 3; i++) {
            System.out.println("hello Thread");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}
public class D2 {
    public static void main(String[] args) throws InterruptedException {
        MyRunnable runnable = new MyRunnable();
        //线程要执行的任务通过Runnable描述
        Thread t = new Thread(runnable);
        t.start();
        for (int i = 0; i < 3; i++) {
            System.out.println("hello main");
            Thread.sleep(1000);
        }
    }
}
3.匿名内部类创建Thread子类对象
public class D3 {
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(){
            @Override
            public void run() {
                for (int i = 0; i < 3; i++) {
                    System.out.println("hello Thread");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        };
        t.start();
        //主线程
        for (int i = 0; i < 3; i++) {
            System.out.println("hello main");
            Thread.sleep(1000);
        }
    }
}
4.匿名内部类创建Runnable子类对象
public class D4 {
    public static void main(String[] args) {
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 3; i++) {
                    System.out.println("hello thread");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        });
        t.start();
        //主线程
        System.out.println("hello main");
    }

}
5.lambda表达式创建Runnable子类对象
public class D5 {
    public static void main(String[] args) {
        Thread t = new Thread(()->{
            for (int i = 0; i < 3; i++) {
                System.out.println("hello Threaad");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        t.start();
        System.out.println("hello main");
    }
}

Thread常见属性

属性 获取方法
ID getId()
名称 getName()
状态 getState()
优先级 getPriority
是否后台线程 isDaemon()

是否存活

isAlive()

是否被中断 isInterrupted

后台线程:线程在执行过程中,不能阻止进程结束。

前台线程:线程在执行过程中,能够阻止进程结束。

start和run

start方法

  1. start方法的作用是真正的去申请系统线程,分配线程资源
  2. 调用start方法后, start方法内部会调用Java 本地方法(封装了对系统底层的调用)真正的启动线程,并执行run方法中的代码,run 方法执行完成后线程进入销毁阶段。

一个Thread对象只能调用一次start。

run方法:

  1. run方法的作用是描述线程具体要执行的任务;
  2. run方法是一个类中的普通方法,主动调用和调用普通方法一样,会顺序执行一次;

线程中断

Java中断一个线程,往往是用一个比较 “温柔的” 方式。通过中断,一个线程可以通知另一个线程,告知它需要停止执行当前任务。

例如,有两个线程A和B,B正在运行,A想要B结束,核心就是A想办法让B的 run方法 执行完毕,此时B自己决定是立即结束还是稍后结束。

在Java中,线程中断是通过调用线程的interrupt()方法来实现的。

public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(()->{
            //先获取到线程的引用
            Thread currentThread = Thread.currentThread();
            while ((!currentThread.isInterrupted())){
                System.out.println("hello thread");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                     //throw new RuntimeException(e);
                    System.out.println("执行catch操作");
                    break;
                }
            }
        });
        t.start();
        Thread.sleep(3000);
        //在主线程中控制t线程被终止 设置上述标志位
        t.interrupt();
    }

currentThread()是Thread类的静态方法,用于获取当前正在执行的线程对象。

interrupt()是Thread类里的一个boolean类型的成员,初始状态是 false ,表示未被终止。

一旦外面的线程调用这个方法,就会被设置标志位。

上述代码中,主线程在调用interrupt方法时,由于判定操作和打印操作执行速度非常快,此时大概率 t 线程正在sleep状态,而interrupt方法不仅能够设置标志位,还能将正在sleep的线程唤醒,此时触发了InterruptedException异常,并被catch住,但是,当sleep等阻塞的函数(wait/join)被唤醒后,会清空刚刚interrupt方法设置的标志位,此时如果catch 中没有break/return,那么循环就不会结束。

此时,如果 t 线程想忽视主线程,catch中可以什么都不做,如果想立即结束,就可以在catch中加上break/return来结束线程,如果要想稍后结束,就可以在catch中写上一些其他逻辑,最后再beak/return

线程等待(join)

操作系统对于多线程的执行是“随机调度,抢占式执行的”,线程等待,就是在确定线程的结束顺序,让后结束的线程等待先结束的线程,此时后结束的线程就会进入阻塞状态,一直到先结束的线程结束,阻塞才会解除。

例如,现在有两个线程 A 和 B,在A线程中调用 B.join,意思就是让 A 线程先等待 B 线程结束,A再继续执行。

public static void main(String[] args) throws InterruptedException {
        //主线程里创建t线程
        Thread t = new Thread(()->{
            for (int i = 0; i < 3; i++) {
                System.out.println("线程t");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            System.out.println("t结束");
        });
        t.start();
        Thread.sleep(4000);

        System.out.println("main等待");
        t.join();
        System.out.println("main结束等待");
    }

上述使用 join() 方法,是无参数的,也就意味着,只要被等待的线程不执行完,等待的线程就会一直阻塞。

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

线程休眠

使用Threaad.sleep()方法可以使线程休眠

try {
      Thread.sleep(1000);
} catch (InterruptedException e) {
      throw new RuntimeException(e);
}

线程执行sleep,就会使这个线程不参与 cpu调度,从而把 cpu 资源让出来,给别人使用,这样的操作称为 “放权”,即放弃使用cpu的权利

线程状态

1.NEW

当前虽然有Thread对象,但是内核的线程还没有(还没调用start)

public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(()->{
            while(true){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        System.out.println(t.getState());
        t.start();
    }
2.TERMINATED

当前Thread对象虽然还在,但是内核的线程已经销毁(线程已经结束了)

public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(()->{
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
        });
        t.start();
        System.out.println(t.getState());
    }
3.RUNNABLE

就绪状态,正在cpu上运行 / 随时可以去cpu上运行

public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(()->{
            while(true){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        t.start();
        System.out.println(t.getState());
    }
4.BLOCKED

因为锁竞争而引起的阻塞

5.TIMED_WAITING

有超时间的等待,比如sleep,或者join带参数版本

public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(()->{
            while(true){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        t.start();
        Thread.sleep(500);
        System.out.println(t.getState());

    }
6.waiting

没有超时间的阻塞等待

public static void main(String[] args) throws InterruptedException {
        Thread mainT = Thread.currentThread();
        Thread t = new Thread(()->{
            while(true){
                try {
                    System.out.println(mainT.getState());
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        t.start();
        //由于t线程是持续while,因此join不会返回
        //观察主线程状态就能看到waiting
        t.join();
    }

上述线程状态,可通过 jconsole 观察。

相关推荐

  1. Thread 基本

    2024-07-20 13:52:01       31 阅读
  2. 总结 Thread 基本

    2024-07-20 13:52:01       34 阅读
  3. Thread基本

    2024-07-20 13:52:01       33 阅读
  4. Python 中 Thread 线程

    2024-07-20 13:52:01       62 阅读
  5. pymysql基本

    2024-07-20 13:52:01       69 阅读
  6. @ConfigurationProperties 基本

    2024-07-20 13:52:01       45 阅读
  7. mysql基本

    2024-07-20 13:52:01       41 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-20 13:52:01       171 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-20 13:52:01       189 阅读
  3. 在Django里面运行非项目文件

    2024-07-20 13:52:01       157 阅读
  4. Python语言-面向对象

    2024-07-20 13:52:01       170 阅读

热门阅读

  1. C?C++?

    2024-07-20 13:52:01       30 阅读
  2. ArcGIS Pro SDK (九)几何 10 弧

    2024-07-20 13:52:01       27 阅读
  3. AB测试介绍

    2024-07-20 13:52:01       36 阅读
  4. MULESOFT

    MULESOFT

    2024-07-20 13:52:01      36 阅读
  5. libevent的事件分发相关接口

    2024-07-20 13:52:01       35 阅读
  6. 082、Python 读文本文件

    2024-07-20 13:52:01       37 阅读
  7. Linux绑定硬件IRQ到指定CPU核

    2024-07-20 13:52:01       34 阅读
  8. 使用内网穿透工具 frp 发布内网 web 站点

    2024-07-20 13:52:01       37 阅读