多线程基础使用

本文详细介绍了Java中线程的六种状态(NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED),以及通过实现Runnable接口、继承Thread类和使用线程池创建线程的不同方式。同时讨论了实现Runnable接口的优势和线程分离的好处。
摘要由CSDN通过智能技术生成

提示:有关线程六大状态, 以及创建线程的五种方法

线程

线程状态

操作系统的线程主要有以下三个状态:

  • 就绪状态(ready):线程正在等待使用 CPU,经调度程序调用之后进入 running 状态。
  • 执行状态(running):线程正在使用 CPU。
  • 等待状态(waiting): 线程经过等待事件的调用或者正在等待其他资源(如 I/O)。

Java中线程层面状态有六种, 其实这里注释很详细, 可以尝试翻译理解

public enum State {
        /**
         * Thread state for a thread which has not yet started.
         */
        NEW,

        /**
         * Thread state for a runnable thread.  A thread in the runnable
         * state is executing in the Java virtual machine but it may
         * be waiting for other resources from the operating system
         * such as processor.
         */
        RUNNABLE,

        /**
         * Thread state for a thread blocked waiting for a monitor lock.
         * A thread in the blocked state is waiting for a monitor lock
         * to enter a synchronized block/method or
         * reenter a synchronized block/method after calling
         * {@link Object#wait() Object.wait}.
         */
        BLOCKED,

        /**
         * Thread state for a waiting thread.
         * A thread is in the waiting state due to calling one of the
         * following methods:
         * <ul>
         *   <li>{@link Object#wait() Object.wait} with no timeout</li>
         *   <li>{@link #join() Thread.join} with no timeout</li>
         *   <li>{@link LockSupport#park() LockSupport.park}</li>
         * </ul>
         *
         * <p>A thread in the waiting state is waiting for another thread to
         * perform a particular action.
         *
         * For example, a thread that has called <tt>Object.wait()</tt>
         * on an object is waiting for another thread to call
         * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
         * that object. A thread that has called <tt>Thread.join()</tt>
         * is waiting for a specified thread to terminate.
         */
        WAITING,

        /**
         * Thread state for a waiting thread with a specified waiting time.
         * A thread is in the timed waiting state due to calling one of
         * the following methods with a specified positive waiting time:
         * <ul>
         *   <li>{@link #sleep Thread.sleep}</li>
         *   <li>{@link Object#wait(long) Object.wait} with timeout</li>
         *   <li>{@link #join(long) Thread.join} with timeout</li>
         *   <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
         *   <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
         * </ul>
         */
        TIMED_WAITING,

        /**
         * Thread state for a terminated thread.
         * The thread has completed execution.
         */
        TERMINATED;
    }

NEW

处于 NEW 状态的线程此时尚未启动。这里的尚未启动指的是还没调用 Thread 实例的start()方法。

RUNNABLE

表示当前线程正在运行中。处于 RUNNABLE 状态的线程在 Java 虚拟机中运行,也有可能在等待 CPU 分配资源。

BLOCKED

阻塞状态。处于 BLOCKED 状态的线程正等待锁的释放以进入同步区。

WAITING

等待状态。处于等待状态的线程变成 RUNNABLE 状态需要其他线程唤醒。

调用下面这 3 个方法会使线程进入等待状态:

  • Object.wait():使当前线程处于等待状态直到另一个线程唤醒它;
  • Thread.join():等待线程执行完毕,底层调用的是 Object 的 wait 方法;
  • LockSupport.park():除非获得调用许可,否则禁用当前线程进行线程调度

TIMED_WAITING

超时等待状态。线程等待一个具体的时间,时间到后会被自动唤醒。

调用如下方法会使线程进入超时等待状态:

  • Thread.sleep(long millis):使当前线程睡眠指定时间;
  • Object.wait(long timeout):线程休眠指定时间,等待期间可以通过notify()/notifyAll()唤醒;
  • Thread.join(long millis):等待当前线程最多执行 millis 毫秒,如果 millis 为 0,则会一直执行;
  • LockSupport.parkNanos(long nanos): 除非获得调用许可,否则禁用当前线程进行线程调度指定时间;
  • LockSupport.parkUntil(long deadline):同上,也是禁止线程进行调度指定时间;

TERMINATED

终止状态。此时线程已执行完毕。

线程状态转化图

image

线程创建使用方式

本质上就两种方式, 一种实现接口, 一种继承Thread

  1. 实现Runnable
class MyRunnable implements Runnable{
    @Override
    public void run() {
        while (true){
            System.out.println("hello thread");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
public class TestDemo2 {
    public static void main(String[] args) {
        Runnable runnable = new MyRunnable();
        Thread t = new Thread(runnable);
        t.start();
        while(true){
            System.out.println("hello main");
            try{
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }
}
  1. 实现Callable
    • 实现Callable是带有返回值的, 可以使用FutureTask封装
public class MyCallable implements Callable<Integer> {
    public Integer call() {
        return 123;
    }
}
------------------------------------------------------------------
public static void main(String[] args) throws ExecutionException, InterruptedException {
    MyCallable mc = new MyCallable();
    FutureTask<Integer> ft = new FutureTask<>(mc);
    Thread thread = new Thread(ft);
    thread.start();
    System.out.println(ft.get());
}


  1. 继承Thread
class MyThread extends Thread{
    @Override
    public void run() {
        System.out.println("hello thread");
    }
}
public class TestDemo {
    public static void main(String[] args) {
        Thread t = new MyThread();//向上转型
        t.start();
    }
}

这里我们为什么使用t.start() 而不是t.run()

  • t.run()只是调用了MyThread中的run方法, 并不是起了一个线程, 这不叫多线程

    image-20240216150249206

  • 而t.start()是真正创建了一个线程

    image-20240216150453910

  1. 线程池

    public class TestDemo3 {
        public static void main(String[] args) {
            Thread t = new Thread(){
                @Override
                public void run() {
                    while(true) {
                        System.out.println("Hello Thread");
                        try{
                            Thread.sleep(1000);
                        }catch (InterruptedException e){
                            e.printStackTrace();
                        }
                    }
                }
            };
            t.start();
        }
    }
    
  2. Lamdba表达式

 public static void main(String[] args) {
        Thread t = new Thread(()->{
            while(true){
                System.out.println("hello thread");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t.run();

    }

实现Runnable和Callable本质上是任务, 可以理解为创建了一个可以在线程中运行的任务, 而不是真正的线程. 而实现Thread才是真正的创建了线程

实现接口和继承Thread哪个更好?

  • 当然是实现接口, Java本身不支持多继承, 继承一个Thread就不能再继承别的了
  • 继承Thread开销过大
  • 接口的写法中线程和任务是分离的。更好的解耦合。关联关系越紧密,就认为耦合性越高。此时线程的内容本身和线程的关系不大。那么以后更改任务不采用多线程执行,代码的改动也不是很大

ps

todo:线程池相关后面补

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值