Thread的基本操作

目录

一 .  创建线程

    1) 继承Thread类 

   2) 使用Runnable 来创建线程

 3) 继承Thread , 使用匿名内部类

 4)  实现Runnable , 使用匿名内部类

5)  lambda 表达式 创建线程(常用)

二 . Thread 构造方法 与 常用方法

1. 无参构造 Thread()

2. 只有Runnable 参数 Thread(Runnable)

 3. 带有Runnable 与 String  的构造方法 Thread(Runnable,String)

4. 只带有String 参数的构造方法 Thread(String)

 ​Thread 常见属性

1) 获得当前线程的引用

2) 获取ID

3) 获取名称

4) 获取优先级

5) 获取线程的状态

6) 是否存活

7)  是否被中断

 8) 是否后台线程

关于线程中的 run() 方法

三 . 线程的状态

1) 线程休眠

2) 线程中断

3) 线程等待

总结 : 


一 .  创建线程

    1) 继承Thread类 

class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("通过继承来创建线程");
    }
}
public class Demo1 {
    public static void main(String[] args) {
        Thread t = new MyThread();
        t.start();
    }
}

   2) 使用Runnable 来创建线程

这种写法通过实现Runnable , 来描述线程中要执行的任务

class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("使用实现Runnable 接口 创建线程");
    }
}
public class Demo2 {
    public static void main(String[] args) {
        Thread t = new Thread(new MyRunnable());
        t.start();
    }
}

 3) 继承Thread , 使用匿名内部类

public class Demo3 {
    public static void main(String[] args) {
        Thread t = new Thread() {
            @Override
            public void run() {
                System.out.println("继承Thread,匿名内部类");
            }
        };
        t.start();
    }
}

 4)  实现Runnable , 使用匿名内部类

实现方法跟上面相同.(实现了Runnable,重写了run()方法)

public class Demo4 {
    public static void main(String[] args) {
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("实现Runnable 接口,匿名内部类");
            }
        });
        t.start();
    }
}

5)  lambda 表达式 创建线程(常用)

public class Demo5 {
    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            System.out.println("lambda表达式");
        });
    }
}

总结 : 通常认为Runnable 这种写法更好一点 ~~ 能够做到让线程和线程执行的任务, 更好的进行解耦.  (写代码希望 : 高内聚, 底耦合)

Runnable 单纯的只是描述了一个任务 ~ 至于这个任务是要通过一个进程来执行,还是线程执行,或者是线程池来执行,还是协程来执行, Runnable本身别不关心,Runnable里面的代码也不关心.

 

二 . Thread 构造方法 与 常用方法

在这里主要将一下几个构造方法 : 

1. 无参构造 Thread()

 

2. 只有Runnable 参数 Thread(Runnable)

 3. 带有Runnable 与 String  的构造方法 Thread(Runnable,String)

4. 只带有String 参数的构造方法 Thread(String)

 ​Thread 常见属性

Thread 的几个常见属性

1) 获得当前线程的引用

Thread.currentThread();

2) 获取ID

3) 获取名称

4) 获取优先级

public static void main(String[] args) {
        Thread t = new Thread(() -> {
            //获取当前线程的ID
            System.out.println(Thread.currentThread().getId());
            //获取当前线程的名称
            System.out.println(Thread.currentThread().getName());
            //获取当前线程的优先级
            System.out.println(Thread.currentThread().getPriority());
            System.out.println("hello");
        });
        t.start();
    }

5) 获取线程的状态

这里的状态会分为很多种,在后面会重点介绍.

6) 是否存活

这里的线程存活指的是系统内核里的那个线程,是否存活的

public static void main(String[] args) {
        Thread t = new Thread(() -> {
            while (true) {
                //空
            }
        });
        System.out.println(t.isAlive());
        t.start();
        System.out.println(t.isAlive());
    }

7)  是否被中断

这是线程中的一个标志位 默认值为false.

public class Demo11 {
    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            System.out.println("hello");
        });
        t.start();
        System.out.println(t.isInterrupted());
    }
}

 我们通过interrupt() 方法就可以将这个标志位由false 变为 true;

public static void main(String[] args) {
        Thread t = new Thread(() -> {
            System.out.println("hello");
        });
        t.start();
        System.out.println(t.isInterrupted());
        t.interrupt();
        System.out.println(t.isInterrupted());
    }

 8) 是否后台线程

什么是前台线程 ??  什么是后台线程??

后台线程不阻止java进程结束.

即使后线程还没执行完, java进程该结束就结束了~~

前台线程更好相反

前台线程会阻止java线程结束, 必须得java进程中所有的前台线程都执行完 java进程才结束.

通过Thread 创建出来的线程都是前台线程,

可以通过setDaemon() 将前台设置为后台

public static void main(String[] args) {
        Thread t = new Thread(() -> {
            while (true) {
                //空
            }
        });
        t.start();
        System.out.println(t.isDaemon());
    }

调用setDaemon()

public static void main(String[] args) {
        Thread t = new Thread(() -> {
            while (true) {
                //空
            }
        });
        System.out.println(t.isDaemon());
        //注意这里在设置前后台线程时
        //这个语句要放在t.start()之前
        t.setDaemon(true);
        t.start();
        System.out.println("结束");
    }

关于线程中的 run() 方法

如果通过 t.run() 去调用 ,  那么它会是一个普通的方法去执行, 存在main线程中

public static void main(String[] args) {
        Thread t = new Thread(() -> {
            int j = 5;
            while (j-- > 0) {
                System.out.println("t:" + j);
            }
        });
        t.run();
        int i = 10;
        while (i-- > 0) {
            System.out.println("main :" + i);
        }
    }

 

通过上述的运行结果我们可以看出,先执行完run()方法,然后再向后执行

如果将t.run() 转换为 t.start()

run() 方法补充 : 

 多线程如何执行 (补充): 

 

三 . 线程的状态

1) 线程休眠

Thread.sleep()  : 让当前线程进入休眠 , 括号里面放入休眠的时间

Thread.sleep(1000) : 让当前线程休眠1秒  

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

hello在打印的时候也是 1秒打印一个

 

2) 线程中断

两种方式 : 1. 自己设立一个标志 来控制线程的运行

                  2. 使用线程中的isInterrupted()

1. 手动设置一个标志位 , 来控制线程是否要结束执行~~

t 线程 与 main 线程  都是在一个进程内, 因此它们用了同一份虚拟地址空间.

因此 , 在main线程中修改的isQuit 就会该变 t 线程中的isQuit.

public class Demo15 {
    public static boolean isQuit = false;
    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            while (!isQuit) {
                System.out.println("hello");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t.start();
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        isQuit = true;
        System.out.println("中断t线程");
    }
}

2. 使用isInterrupted() 来修改线程的标志位

public class Demo16 {
    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            while (!Thread.currentThread().isInterrupted()) {
                System.out.println("hello");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t.start();
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        t.interrupt();
        System.out.println("-----");
    }
}

通过上述的输出结果 : 代码报错之后 , 没有中断 t 线程,还是在继续的执行程序

问题如下 :

修改后的代码 : 

public class Demo16 {
    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            while (!Thread.currentThread().isInterrupted()) {
                System.out.println("hello");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    break;
                }
            }
        });
        t.start();
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        t.interrupt();
        System.out.println("-----");
    }
}

 

这样当它打印完异常日志后 , 我们直接让它break 退出循环.

3) 线程等待

实现一个代码通过 t 线程让i 自增10次

public class Demo17 {
    private static int i = 0;
    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            for (int j = 0; j < 10; j++) {
                i++;
            }
        });
        t.start();
        System.out.println(i);
        System.out.println("main线程结束");
    }
}

 输出结果为 0 

问题如下 : 

 修改代码 : 

public class Demo17 {
    private static int i = 0;
    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            for (int j = 0; j < 10; j++) {
                i++;
            }
        });
        t.start();
        try {
            t.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(i);
        System.out.println("main线程结束");
    }
}

对于线程等待的补充 : 

上述 t.join()  这句代码是在main线程中, 因此就是让main线程等待 t 线程执行完成.

要注意这里的等待与被等待对象.

另外我们还可以设置等待的时间

t.join(2000) : 表示main线程只等待 t 线程2秒钟. 然后就继续去执行main方法其余语句.

总结 : 

综上的线程的状态, 我们可以构造一个图

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.kler.cn/a/1140.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

QT入门Item Views之QListView

目录 一、QListView界面相关 1、布局介绍 二、代码展示 1、创建模型&#xff0c;导入模型 2、 设置隔行背景色 3、删除选中行 三、源码下载 此文为作者原创&#xff0c;创作不易&#xff0c;转载请标明出处&#xff01; 一、QListView界面相关 1、布局介绍 先看下界面…

内存泄漏定位工具之 valgrind

内存泄漏检测工具 文章目录内存泄漏检测工具一、valgrind介绍1. memcheck2. cachegrind3. helgrind二、源码下载三、命令操作1.memcheck 工具四、虚拟机下使用1. x86编译2. 正常程序测试3. 申请内存不释放测试4. 内存越界的测试5. 读写已经释放的内存五、ARM平台使用1.交叉编译…

ARM uboot 的移植4 -从 uboot 官方标准uboot开始移植

一、添加DDR初始化1 1、分析下一步的移植路线 (1) cpu_init_crit 函数成功初始化串口、时钟后&#xff0c;转入 _main 函数&#xff0c;函数在 arch/arm/lib/crt0.S 文件中。 (2) 在 crt0.S 中首先设置栈&#xff0c;将 sp 指向 DDR 中的栈地址&#xff1b; #if defined(CONF…

JetPack Compose入门知识

1. Jetpack Compse是什么 Jetpack Compose 是Android新一代UI开发框架&#xff0c;采用声明式开发范式&#xff0c;开发者只需要将注意力放在如何编写UI界面上&#xff0c;当需要渲染的数据发生变化时&#xff0c;框架会自动完成UI刷新&#xff0c;其次它使用Kotlin DSL来编写…

【工作中问题解决实践 七】SpringBoot集成Jackson进行对象序列化和反序列化

去年10月份以来由于公司和家里的事情太多&#xff0c;所以一直没有学习&#xff0c;最近缓过来了&#xff0c;学习的脚步不能停滞啊。回归正题&#xff0c;其实前年在学习springMvc的时候也学习过Jackson【Spring MVC学习笔记 五】SpringMVC框架整合Jackson工具&#xff0c;但是…

Github的使用

Github Date: March 8, 2023 Sum: Github的使用 Github 了解开源相关的概念 1. 什么是开源 2. 什么是开源许可协议 开源并不意味着完全没有限制&#xff0c;为了限制使用者的使用范围和保护作者的权利&#xff0c;每个开源项目都应该遵守开源许可协议&#xff08; Open Sou…

深入底层——浅谈Vue2和Vue3的响应式数据实现原理

深入底层——浅谈Vue2和Vue3的响应式数据实现原理1、Vue2响应式数据存在的问题2、Vue2为什么监测不到属性变更3、Vue3是否存在该问题4、Vue3是如何做数据响应式的5、拓展5.1、Proxy代理对象5.2、Reflect反射对象6、总结1、Vue2响应式数据存在的问题 在vue2当中是如何做到更改数…

SpringCloud微服务技术栈.黑马跟学(一)

SpringCloud微服务技术栈.黑马跟学一微服务技术栈导学为什么学&#xff1f;学哪些&#xff1f;怎么学&#xff1f;1.认识微服务1.1.学习目标1.2.单体架构1.3.分布式架构1.4.微服务1.5.SpringCloud1.6.总结2.服务拆分和远程调用2.1.服务拆分原则2.2.服务拆分示例2.2.1.导入Sql语…

Threadlocal相关问题

Threadlocal相关问题 ​ 核心问题 ​ 1、 什么是ThreadLocal&#xff1f;核心方法有哪些&#xff1f; ​ 2、使用 拦截器 ThreadLocal 处理鉴权的整体流程是什么样的&#xff1f; ​ 3、代码编写实现流程有哪些&#xff1f; 面试相关 ​ ThreadLocal内存泄漏问题 ​ 1&…

jmeter使用json后置处理器变量使用

目录 1、json后置处理器添加 2、后置处理器说明 3、环境变量设置 4、设置全局使用变量 1、json后置处理器添加 json后置处理器位置在线程组或者线程组下的请求中都可添加 2、后置处理器说明 1、json后置处理器如果放在线程组的外面&#xff0c;则是所有线程组都可以使用&a…

什么是栈,如何实现?

欢迎来到 Claffic 的博客 &#x1f49e;&#x1f49e;&#x1f49e; “但有一枝堪比玉&#xff0c;何须九畹始征兰?” 前言&#xff1a; 栈是一种特殊的线性表&#xff0c;就像开盖的桶一样&#xff0c;从底部开始放数据&#xff0c;从顶部开始取数据&#xff0c;那么栈具体是…

【AI 工具】文心一言内测记录

文章目录一、申请内测二、收到内测邀请三、激活内测四、开始使用1、普通对话2、生成图片3、生成代码4、写剧本5、生成小说五、问题反馈一、申请内测 到 https://yiyan.baidu.com/welcome 页面 , 点击 " 开始体验 " 按钮 , 申请试用 ; 申请时 , 需要填写相关信息 ; 主…

【Linux】linux中vim/vi (linux基本开发工具)

vim键盘图这是vim/vi的键盘图&#xff0c;基本的一些操作&#xff0c;上面都标识的比较清晰。编辑vim基本概念2.1.介绍vi/vim的区别简单点来说&#xff0c;它们都是多模式编辑器&#xff0c;不同的是vim是vi的升级版本&#xff0c;它不仅兼容vi的所有指令&#xff0c;而且还有一…

2023最新性能测试八股文【附答案】,软测人必备!

1. 请描述什么是性能测试、什么是负载测试、什么是压力测试&#xff1f;【参考答案】性能测试&#xff1a;性能测试是和功能测试相对应的。根据用户场景进行的单个用户操作&#xff0c;是属于功能测试领域&#xff0c;主要是验证软件是否可以满足用户的功能需求。比如&#xff…

机器学习基础方法与概论(四)(决策树基本概念、特征选择、ID3、C4.5、剪枝、CART算法)

文章目录决策树模型与学习决策树模型决策树与 if-then 规则决策树学习特征选择决策树的生成ID3 算法C4.5 算法决策树的剪枝CART 算法CART 生成回归树的生成分类树的生成CART 剪枝References决策树模型与学习 决策树模型 分类决策树模型是一种描述对实例进行分类的树形结构。决…

PWM应用

目录 一、应用层操控 PWM 控制pwm 二、编写代码 一、应用层操控 PWM 与 LED 设备一样&#xff0c; PWM 同样也是通过 sysfs 方式进行操控&#xff0c;进入到/sys/class/pwm 目录下&#xff0c;如下所示&#xff1a; 这八个文件夹其实就对应了 I.MX6U的 8 个 PWM 控制器&…

【C++】搜索二叉树(保姆教程)

&#x1f345;二叉树底层是堆&#xff0c;之前学习的简单二叉树不是大堆就是小堆&#xff0c;今天是二叉树进阶&#xff0c;一定要好好掌握&#xff01; 目录 ☃️1.搜索二叉树介绍 ☃️2.底层实现 ☃️3.key模型和key&#xff0c;value模型 ☃️1.搜索二叉树介绍 右>根&…

Selenium基础篇之环境准备

文章目录前言一、Selenium是什么&#xff1f;二、浏览器驱动下载1.安装一个支持的浏览器2.查看浏览器的版本3.下载浏览器驱动4.驱动位置放置4.1 放在代码文件同级目录4.2 随意放置4.3 放在python解释器根目录三、安装selenium1.安装2.查看版本四、使用selenium前言 大家好&…

Linux——进程管理篇(详解fork和exec)

文章目录Linux——进程管理篇&#xff08;详解fork和exec&#xff09;&#x1f697;如何在Linux编写与运行代码编写编译运行&#x1f697;进程管理forksystemexec&#x1f697;总结Linux——进程管理篇&#xff08;详解fork和exec&#xff09; &#x1f680;&#x1f680;这篇…

前端代码复用学习笔记:整洁架构与清晰架构

基础代码的复用往往比较简单&#xff0c;但是业务代码的复用通常是困难的&#xff0c;如果没有特殊的手段去治理项目会逐渐发展为难以维护的巨石应用&#xff0c;按照维基百科记载&#xff0c;代码的复用形式主要有三种&#xff0c;程序库&#xff0c;应用框架&#xff0c;设计…
最新文章