多线程初阶——线程状态

多线程初阶——线程状态

1.Thread类及常见构造方法

方法说明
Thread()默认无参构造方法
Thread(Runnable target)使用Runnable对象创建线程对象
Thread(String name)创建线程对象,并给线程起名字
Thread(Runnable target,String name)使用Runnable对象创建线程对象,并给线程起名字

给线程起名字

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

            }
        },"线程一");
        t.start();
        while (true){
            System.out.println("main");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

image-20230129200540985

2.Thread常见的方法

属性方法
IDgetId()
名称getName()
状态getState()
优先级getPriority()
是否后台线程isDaemon()
是否存活isAlive()
是否被中断isInterrupted()

说明

getId()

ID是线程唯一标识,不同线程不会重复

getName()

线程的名称

getState()

表示线程当前所处的一个情况

getPriority()

获得线程的优先级

isDaemon()

JVM会在一个进程的所有非后台线程结束后,才会结束运行,这里的后台,和我们常说的手机后台应用类似线程创建的时候,默认是一个前台线程,前台线程可以阻止进程的退出,后台线程不影响进程的退出

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

image-20230129214257735

由于线程是前台进程,需要等待运行结束,进程才结束。代码为死循环,所以将会一直执行。

利用setDaemom()方法将线程设置为后台进程,等主线程执行完,进程就结束了,注意:先设置后台进程,再启动线程

public class Demo5 {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            while (true) {
                System.out.println("thread...");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        thread.setDaemon(true);
        thread.start();
        System.out.println("main.....");

    }
}

image-20230129215820274

3.线程相关的重要操作

3.1启动线程—start()

创建Thread对象、重写run方法,只是给线程安排了任务,并没有执行,而调用start方法,才是创建出了线程

3.2中断线程

**线程结束其实就是让线程的入口方法执行完 **

而中断线程,其实就是让线程停止下来,结束入口方法的执行

有2种方法可以中断线程

**方法一:直接用自定义的变量来作为标志位 **

需要给标志位上加volatile关键字

这里我们以李四在银行取钱为例

public class Demo8 {
    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(5 * 1000);
        System.out.println(Thread.currentThread().getName()
                + ": 老板来电话了,得赶紧通知李四对方是个骗子!");
        target.isQuit = true;
    }
}

image-20230203010328854

方法二:使用Thread自带的标志位

Thread.interrupted()或者Thread.currenThread().isInterrupted()

public class Demo9 {
 private static class MyRunnable implements Runnable {

     @Override
     public void run() {
         while (!Thread.currentThread().isInterrupted()) {
             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(5 * 1000);
        System.out.println(Thread.currentThread().getName()
                + ": 老板来电话了,得赶紧通知李四对方是个骗子!");
        thread.interrupt();
    }
}

运行结果

image-20230203204711356

这时抛出了InterruptedException异常

这是为什么呢?

由于线程的有效任务是打印一句话,这个操作耗时比较小,大部分时间线程都在sleep状态,正常来说,当线程在运行真正有效任务时去中断才是一个有效的中断,而在线程休眠的时候中断,其实是把休眠给中断了,而休眠本身没有到指定的时间,所以抛出了InterruptedException异常

当我们去掉线程中的休眠时,结果如下

image-20230203220249387

这时候线程才真正的中断了

3.3 等待线程— join()

我们知道线程之间的执行顺序是根据系统调度随机执行的,但有时我们需要等待一个线程执行完,再执行下一个线程,这时我们需要一个方法明确等待线程结束

public class Demo10 {
    public static void main(String[] args) throws InterruptedException {
        Runnable target = () -> {
            for (int i = 0; i < 3; i++) {
                System.out.println(Thread.currentThread().getName() + ":正在工作!");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName() + "结束了工作");
        };
        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("王五结束了工作");
    }
}

image-20230203221145829

join()其他方法

public void join()等待线程结束(一直等,知道线程执行的任务结束)
public void join(long millis)等待线程结束,但等待millis毫秒
public void join(long millis, int nanos)同理

3.4 获取线程引用

private static Thread currentThread()

返回当前线程对象的引用

3.5休眠线程—sleep()

让线程休眠休眠一会

图解sleep()的具体使用

image-20230204002702109

4.线程的状态

在Java线程分为6种状态

1. NEW:创建好了一个Java的Thread对象,并安排好了任务,没有调用start()方法之前,和PCB没有关系

2. RUNNABLE:运行+就绪状态,在执行任务时的一个常态之一

3. TIMED_WAITING:指定了一个时间的阻塞队列,过时不候

4. WAITING :没有指定时间的等待,一直死等

5. BLOCK:等待锁的状态

6. TERMINATED :结束,完成状态,PCB已经被销毁了,但是Java对象还在

查看线程状态

public class Demo14 {
    public static void main(String[] args) throws InterruptedException {
        Thread thread=new Thread(()->{
            for (int i = 0; i < 5; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        System.out.println("线程创建之前:"+thread.getState());
        thread.start();
        Thread.sleep(1000);
        System.out.println("启动线程,创建好PCB后:"+thread.getState());
        thread.join();
        System.out.println("线程执行完成后:"+thread.getState());
    }
}

image-20230204004138603

线程之间相互转换

image-20230204004728035
觉得不错就留下你的三连吧

  • 16
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 11
    评论
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小 王

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值