并发编程之创建线程和线程的状态

news/2024/6/17 23:26:00 标签: java, 开发语言

创建线程的三种方式

1.继承Thread类 重写run方法

java">class MyThread extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(getName() + ":打了" + i + "个小兵");
        }
    }
}
public class Test {
    public static void main(String[] args) {
        //创建MyThread对象
        MyThread t1=new  MyThread();
        MyThread t2=new  MyThread();
        MyThread t3=new  MyThread();
        //设置线程的名字
        t1.setName("鲁班");
        t2.setName("刘备");
        t3.setName("亚瑟");
        //启动线程
        t1.start();
        t2.start();
        t3.start();
    }
}

2.实现eunnable 重写run方法

java"> class MyRunnable implements Runnable {

    public void run() {
        for (int i = 0; i < 10; i++) {
            try {//sleep会发生异常要显示处理
                Thread.sleep(20);//暂停20毫秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "打了:" + i + "个小兵");
        }
    }
}

public class Test {
    public static void main(String[] args) {

        //创建MyRunnable类
        MyRunnable mr = new MyRunnable();
        //创建Thread类的有参构造,并设置线程名
        Thread t1 = new Thread(mr, "张飞");
        Thread t2 = new Thread(mr, "貂蝉");
        Thread t3 = new Thread(mr, "吕布");
        //启动线程
        t1.start();
        t2.start();
        t3.start();

  
    }
}
java">class CallerTask implements Callable<String> {
    public String call() throws Exception {
        return "Hello,i am running!";
    }

    public static void main(String[] args) {
        //创建异步任务
        FutureTask<String> task=new FutureTask<String>(new CallerTask());
        //启动线程
        new Thread(task).start();
        try {
            //等待执行完成,并获取返回结果
            String result=task.get();
            System.out.println(result);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

注意!!:以上两种方式都是要调用start方法,才能真正实现多线程。直接调用run相当于调用普通方法

线程状态

java">// Thread.State 源码
public enum State {
    NEW,
    RUNNABLE,
    BLOCKED,
    WAITING,
    TIMED_WAITING,
    TERMINATED;
}

NEW状态

表示线程已经被创建,但是还未被启动

测试在start之前调用getState查看状态,是NEW

java">  Thread t1 = new Thread(mr, "张飞");
        Thread t2 = new Thread(mr, "貂蝉");
        Thread t3 = new Thread(mr, "吕布");
        System.out.println(t1.getState());

        //启动线程
        t1.run();

Runnable状态

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

在操作系统层面,线程状态包括ready和running,但是在JVM层面,只能看到Runnable状态,也就是将这两种状态统称为Runnable(运行中)。

Runnable状态可以由NEW状态调用start方法转变过来,但是:

  1. 反复调用同一个线程的 start 方法不可行,回抛出异常
  2. 假如一个线程执行完毕(此时处于 TERMINATED 状态),再次调用这个线程的 start 方法也不可行

看下面的start代码,每次进入会判断threadStatus变量,这个变量代表当前线程的状态。如果线程已经启动或者已经终止,threadStatus就不等于0,进入start就会 throw  IllegalThreadStateException();

java">// 使用synchronized关键字保证这个方法是线程安全的
public synchronized void start() {
    // threadStatus != 0 表示这个线程已经被启动过或已经结束了
    // 如果试图再次启动这个线程,就会抛出IllegalThreadStateException异常
    if (threadStatus != 0)
        throw new IllegalThreadStateException();

    // 将这个线程添加到当前线程的线程组中
    group.add(this);

    // 声明一个变量,用于记录线程是否启动成功
    boolean started = false;
    try {
        // 使用native方法启动这个线程
        start0();
        // 如果没有抛出异常,那么started被设为true,表示线程启动成功
        started = true;
    } finally {
        // 在finally语句块中,无论try语句块中的代码是否抛出异常,都会执行
        try {
            // 如果线程没有启动成功,就从线程组中移除这个线程
            if (!started) {
                group.threadStartFailed(this);
            }
        } catch (Throwable ignore) {
            // 如果在移除线程的过程中发生了异常,我们选择忽略这个异常
        }
    }
}

BLOCK

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

WAITING

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

BLOCK和WAITING有哈区别?

TIMED_WAITING

TIMED_WAITING(超时等待) 状态相当于在等待状态的基础上增加了超时限制,比如通过 sleep(long millis)方法或 wait(long millis)方法可以将线程置于 TIMED_WAITING 状态。当超时时间结束后,线程将会返回到 RUNNABLE 状态。

线程状态的转变

线程状态转换图

 


http://www.niftyadmin.cn/n/4940792.html

相关文章

QML与C++交互

目录 1 QML获取C的变量值 2 QML获取C创建的自定义对象 3 QML发送信号绑定C端的槽 4 C端发送信号绑定qml端槽 5 C调用QML端函数 1 QML获取C的变量值 QQmlApplicationEngine engine; 全局对象 上下文属性 QQmlApplicationEngine engine; QQmlContext *context1 engine.…

HTTP2协议介绍

前言 HTTP是现代互联网通信的基础协议之一&#xff0c;早在1991年&#xff0c;HTTP/0.9版本就诞生了&#xff0c;之后又陆续发布了HTTP/1.0和HTTP/1.1&#xff0c;为互联网应用提供了更高效和可靠的通信方式。 随着时间的推移&#xff0c;互联网的规模和复杂性不断扩大&#x…

深入理解索引B+树的基本原理

目录 1. 引言 2. 为什么要使用索引&#xff1f; 3. 索引的概述 4. 索引的优点是什么&#xff1f; 4.1 降低数据库的IO成本&#xff0c;提高数据查找效率 4.2 保证数据库每一行数据的唯一性 4.3 加速表与表之间的连接 4.4 减少查询中分组与排序的执行时间 5. 索引的缺点…

常见的 JavaScript 框架比较

以下是10种常见的JavaScript框架的比较&#xff1a; React&#xff1a;是由Facebook开发和维护的开源JavaScript库&#xff0c;用于构建用户界面。它允许你使用组件来构建复杂的UI&#xff0c;并专注于每个组件的内部逻辑&#xff0c;而不必担心管理整个应用程序的状态。WebBu…

python使用装饰器记录方法耗时

思路 python使用修饰器记录方法耗时&#xff0c;目的是每当方法执行完后&#xff0c;可以记录该方法耗时&#xff0c;而不需要在每个方法的执行前后&#xff0c;去创建一个临时变量&#xff0c;来记录耗时。 方式一&#xff08;不推荐&#xff09;&#xff1a; 在每个方法的…

(更新中)GIT常用场景

GIT常用场景 - 目录&#xff1a; 00 - 环境配置 01 - 工作区、暂存区、版本库、远程仓库 - 以一次连贯的提交操作为例 02 - git 文件重命名 03 - 通过git log可以查看版本演变历史 04 - 分离头指针情况、理解HEAD和branch 05 - 研究 .git 目录 06 - 文件的差异和恢复 07 - 查看…

快速幂典型

题目描述 求 a 乘 b 对 p 取模的值&#xff0c;其中 1≤a,b,p≤1018。 输入描述: 第一行a&#xff0c;第二行b&#xff0c;第三行p。 输出描述: 一个整数&#xff0c;表示abmodp的值。 示例1 输入 2 3 9 输出 6 #include<bits/stdc.h> using namespace std; t…

正中优配:超470份半年报出炉!多家龙头公司表现亮眼

到8月15日记者发稿&#xff0c;A股共有474家上市公司对外披露了2023年半年报&#xff0c;其间270家完结净利润同比增加&#xff0c;占比到达56.96%。陈述期内&#xff0c;净利润同比增幅居前的上市公司首要会集在酒店餐饮、旅行及景区、光伏设备、轿车零部件等职业。 270家A股上…