Java中线程的常用操作-后台线程、自定义线程工厂ThreadFactpry、join加入一个线程、线程异常捕获

场景

Java中Thread类的常用API以及使用示例:

Java中Thread类的常用API以及使用示例_霸道流氓气质的博客-CSDN博客

上面讲了Thread的常用API,下面记录下线程的一些常用操作。

注:

博客:
霸道流氓气质的博客_CSDN博客-C#,架构之路,SpringBoot领域博主

实现

后台线程

后台线程,是指运行时在后台提供的一种服务线程,这种线程不是属于必须的。

当所有非后台线程结束时,程序就停止了,同时会终止所有的后台线程。

即只要有任何非后台线程还在运行,程序就不会终止。

实现方式:

            Thread daemon = new Thread(new SimpleDaemons());
            daemon.setDaemon(true);

示例代码:

public class SimpleDaemons implements Runnable{

    @Override
    public void run() {
        while(true){
            try {
                TimeUnit.MILLISECONDS.sleep(100);
                System.out.println(Thread.currentThread()+":"+this);
            } catch (InterruptedException e) {
                System.out.println("sleep() interrupted");
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < 10; i++) {
            Thread daemon = new Thread(new SimpleDaemons());
            daemon.setDaemon(true);
            daemon.start();
        }
        System.out.println("all daemons started");
        TimeUnit.MILLISECONDS.sleep(175);
    }
}

说明:

在每次的循环中会创建10个线程,并把每个线程设置为后台线程,然后开始运行,for循环会进行十次,

然后输出信息,随后主线程休眠一段时间后停止运行。在每次run循环中,都会打印当前线程的信息,

主线程运行完毕,程序就执行完毕了。因为daemon是后台线程,无法影响主线程的执行。但是当你把daemon.setDaemon(true)去掉时,

while(true)会进行无限循环,那么主线程一直在执行重要的任务,所以会一直循环下去无法停止。

线程工厂ThreadFactory

按需要创建线程的对象。使用线程工厂替代了Thread或者Runnable接口的硬连接,

使程序能够使用特殊的线程子类,优先级等。ThreadFactory是一个接口,

它只有一个方法就是创建线程的方法。

示例代码一:

上面实现后台线程可以通过线程工厂实现

import java.util.concurrent.ThreadFactory;

public class DaemonThreadFactory implements ThreadFactory {
    @Override
    public Thread newThread(Runnable r) {
        Thread thread = new Thread(r);
        thread.setDaemon(true);
        return thread;
    }
}

然后新建线程池时传递线程工厂

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class DaemonFromFactory implements Runnable{
    @Override
    public void run() {
        while (true){
            try {
                TimeUnit.MILLISECONDS.sleep(100);
                System.out.println(Thread.currentThread()+":"+this);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        ExecutorService executorService = Executors.newCachedThreadPool(new DaemonThreadFactory());
        for (int i = 0; i < 10; i++) {
            executorService.execute(new DaemonFromFactory());
        }
        System.out.println("all daemons started");
        TimeUnit.MILLISECONDS.sleep(500);
    }
}

示例代码二:

创建线程池时如果不指定线程工厂会使用默认的线程工厂,查看ThreadPoolExecutor的构造方法源码

 

Executors.defaultThreadFactory()的源码实现

 

假如我们要自定义线程池的线程名称前缀,可以参考DefaultThreadFactory自定义线程工厂来实现,方便

出现异常时能快速定位。

public class MyThreadFactory implements ThreadFactory {

    private static final AtomicInteger poolNumber = new AtomicInteger(1);
    private final ThreadGroup group;
    private final AtomicInteger threadNumber = new AtomicInteger(1);
    private final String namePrefix;

    public MyThreadFactory(String threadName) {
        SecurityManager s = System.getSecurityManager();
        group = (s !=null)?s.getThreadGroup():Thread.currentThread().getThreadGroup();
        if(threadName == null || threadName.isEmpty()){
            threadName = "pool";
        }
        namePrefix = threadName + poolNumber.getAndIncrement()+"-thread-";
    }

    @Override
    public Thread newThread(Runnable r) {
        Thread t = new Thread(group,r,namePrefix+threadNumber.getAndIncrement(),0);
        if(t.isDaemon()){
            t.setDaemon(false);
        }
        if(t.getPriority()!= Thread.NORM_PRIORITY){
            t.setPriority(Thread.NORM_PRIORITY);
        }
        return t;
    }
}

然后在新建线程池时

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class MyThreadFactoryDemo {
    public static final ThreadPoolExecutor pool = new ThreadPoolExecutor(5,10,5, TimeUnit.SECONDS,new ArrayBlockingQueue<>(100),new MyThreadFactory("badao"));

    public static void main(String[] args) {
        pool.execute(()->{
            Integer integer = getOrderInfo();
        });
    }
    private static Integer getOrderInfo(){
        try {
            List<Integer> list = new ArrayList<>();
            for (int i = 0; i < 10; i++) {
                list.add(i);
            }
            return list.get(11);
        }catch (Exception exception){
            throw new IndexOutOfBoundsException("数组越界");
        }
    }
}

这样在出现数组越界时,就会以指定前缀提示

 

join()方法加入一个线程

一个线程可以在其他线程上调用join()方法,其效果是等待一段时间直到第二个线程执行结束才正常执行。

如果某个线程在另一个线程t上调用t.join()方法,此线程将被挂起,直到目标线程t结束才恢复,

可以用t.isAlive返回为真假判断。也可以在调用join时带上一个超时参数,来设置到期时间,时间到期,join方法自动返回

对join的调用也可以被中断,做法是在线程上调用interrupted方法,这时需要用到try...catch子句。

示例代码:

public class TestJoinMethod  extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            try {
                TimeUnit.MICROSECONDS.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println(Thread.currentThread() +" "+i);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        TestJoinMethod joinMethod = new TestJoinMethod();
        TestJoinMethod joinMethod1 = new TestJoinMethod();
        TestJoinMethod joinMethod2 = new TestJoinMethod();
        joinMethod.start();
        joinMethod.join();
        joinMethod1.start();
        joinMethod2.start();
    }
}

上面加了join的运行结果:

    //Thread[Thread-0,5,main] 0
    //Thread[Thread-0,5,main] 1
    //Thread[Thread-0,5,main] 2
    //Thread[Thread-0,5,main] 3
    //Thread[Thread-0,5,main] 4
    //Thread[Thread-1,5,main] 0
    //Thread[Thread-2,5,main] 0
    //Thread[Thread-2,5,main] 1
    //Thread[Thread-1,5,main] 1
    //Thread[Thread-2,5,main] 2
    //Thread[Thread-1,5,main] 2
    //Thread[Thread-1,5,main] 3
    //Thread[Thread-2,5,main] 3
    //Thread[Thread-1,5,main] 4
    //Thread[Thread-2,5,main] 4

如果将join去掉后的运行结果:

    //Thread[Thread-0,5,main] 0
    //Thread[Thread-1,5,main] 0
    //Thread[Thread-2,5,main] 0
    //Thread[Thread-0,5,main] 1
    //Thread[Thread-1,5,main] 1
    //Thread[Thread-2,5,main] 1
    //Thread[Thread-0,5,main] 2
    //Thread[Thread-2,5,main] 2
    //Thread[Thread-1,5,main] 2
    //Thread[Thread-0,5,main] 3
    //Thread[Thread-1,5,main] 3
    //Thread[Thread-2,5,main] 3
    //Thread[Thread-0,5,main] 4
    //Thread[Thread-1,5,main] 4
    //Thread[Thread-2,5,main] 4

可以看到joinMethod.start();当中的所有的内容都执行完后,才轮到后面的joinMethod1.start();和joinMethod2.start();执行。

换句话说,它会导致当前运行的线程停止运行,直到它加入的线程完成其任务。

线程异常捕获

由于线程的本质,使你不能捕获从线程中逃逸的异常,一旦异常逃出任务的run方法,它就会向外传播到控制台,除非你采用特殊的步骤

捕获这种错误的异常。下面的任务会在run方法的执行期间抛出一个异常,并且这个异常会抛出到run方法的外面,

而且main方法无法对它进行捕获。

public class ExceptionThread implements Runnable{
    @Override
    public void run() {
        throw new RuntimeException();
    }

    public static void main(String[] args) {
        try {
            ExecutorService executorService = Executors.newCachedThreadPool();
            executorService.execute(new ExceptionThread());
        }catch (Exception exception){
            System.out.println(exception);
        }
    }
}

为了解决这个问题,我们需要修改Executor产生线程的方式,java5提供了一个新的接口Thread.UncaughtExceptionHandler,

它允许你在每个Thread上都附着一个异常处理器。Thread.UncaughtExceptionHandler.uncaughtException()会在线程因

未捕获临近死亡时被调用

下面模拟抛出异常

public class ExceptionThread2 implements Runnable{
    @Override
    public void run() {
        Thread t = Thread.currentThread();
        System.out.println("run() by" + t);
        System.out.println("eh = "+t.getUncaughtExceptionHandler());
        //手动抛出异常
        //throw new RuntimeException();
        int a = 1/0;
    }
}

然后实现Thread.UncaughtExceptionHandler接口,创建异常处理器

public class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler{
    @Override
    public void uncaughtException(Thread t, Throwable e) {
        System.out.println("caught "+ e);
    }
}

自定义线程工厂

import java.util.concurrent.ThreadFactory;

public class HandlerThreadFactory implements ThreadFactory {
    @Override
    public Thread newThread(Runnable r) {
        System.out.println(this +"creating new Thread");
        Thread t = new Thread(r);
        System.out.println("created "+t);
        t.setUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
        System.out.println("ex = "+t.getUncaughtExceptionHandler());
        return t;
    }
}

新建线程池并调用

public class CaptureUncaughtException {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool(new HandlerThreadFactory());
        executorService.execute(new ExceptionThread2());
    }
}

运行结果

 

在程序中添加了额外的追踪机制,用来验证工厂创建的线程会传递给UncaughtExceptionHandler,

可以看到未捕获的异常是通过uncaughtException来捕获的。

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

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

相关文章

Win10,详细永久关闭更新方法(附图文)

一、服务设置 1.同时按下键盘 Win R&#xff0c;打开运行对话框&#xff0c;然后输入命令 services.msc &#xff0c;点击下方的“确定”打开服务。 2.找到 Windows Update 这一项&#xff0c;并双击打开。 3.停止该服务&#xff0c;启动类型设置为禁用 4.点击恢复&#…

完整指南:如何安装Man手册

Man手册简介 man手册是Unix和类Unix操作系统中的命令行工具&#xff0c;用于提供关于特定命令、函数和文件的帮助文档。它通常包含命令的语法、选项、参数、示例以及其他相关信息。man手册可以通过在终端输入"man"命令&#xff0c;后跟要查看的命令或函数名称来访问…

惠普Probook455电脑开机突然卡住无法进入桌面

惠普Probook455电脑开机突然卡住无法进入桌面解决方法分享。最近有用户使用的惠普Probook455电脑在开机的时候&#xff0c;电脑一直卡在开机的界面上&#xff0c;无法进入到系统中。无论是重启还是安全模式都无法解决问题。那么遇到这个情况怎么去进行问题的解决&#xff0c;来…

远程组态管理的好处

远程组态管理可以简化管理工作&#xff0c;帮助您节省时间和金钱。远程组态管理可以通过各种应用程序来实现&#xff0c;包括&#xff1a; •监控所有设备的状态&#xff0c;以确保它们正常工作。 •记录现场数据&#xff0c;例如温度&#xff0c;压力或流量。 •快速、轻松地…

CSDN粉丝首破一千关,有你名字

2023-4-11&#xff0c;CSDN粉丝首破一千关。 感谢词版本1,哈哈哈哈哈哈哈哈 在编程世界里&#xff0c;人们可以像创造生命一样创造程序&#xff0c;而我对这种创造和创新的热情&#xff0c;从我的csdn博客社区粉丝首次突破一千人的消息中得到了极大的满足和激励。作为一个Pyth…

全面解析反欺诈(羊毛盾)API,助你识别各类欺诈风险

前言 反欺诈&#xff08;羊毛盾&#xff09;反机器欺诈 API&#xff0c;是一种基于大数据分析和模型产品的技术&#xff0c;通过输入手机号、手机 IP 地址进行检测&#xff0c;帮助客户识别大量存在恶意的账号。 反欺诈&#xff08;羊毛盾&#xff09;API 的作用 反欺诈&…

智慧工厂可视化合集,推动行业数字化转型

图扑软件基于 HTML5&#xff08;Canvas/WebGL/WebVR&#xff09;标准的 Web 技术&#xff0c;满足了工业物联网跨平台云端化部署实施的需求&#xff0c;以低代码的形式自由构建三维数字孪生、大屏可视化、工业组态等等。从 SDK 组件库&#xff0c;到 2D 和 3D 编辑&#xff0c;…

【Camunda】 -- Docker 安裝及使用

【Camunda】 -- Docker 安裝及使用1. Docker install Camunda platform1.1 Web2. Big Data -- Postgres1.1 Big Data -- Postgres3.Awakening1.1 Big Data -- PostgresCamunda platform 是一個任務監控的平台。 Camunda Modeler是建模工具。 1. Docker install Camunda platfor…

SpringSecurity之基础认知

前言 之前一直说开一个SpringSecurity的专栏&#xff0c;今天抽空整理一下&#xff0c;准备开始更新。 也欢迎大家订阅此专栏&#xff01; 什么是SpringSecurity&#xff1f; Spring是非常成功的Java应用框架&#xff0c;目前是非常主流的开发框架。Spring Securtiy正是我们…

基于K-最近邻算法构建红酒分类模型

基于K-最近邻算法构建红酒分类模型 描述 Wine红酒数据集是机器学习中一个经典的分类数据集&#xff0c;它是意大利同一地区种植的葡萄酒化学分析的结果&#xff0c;这些葡萄酒来自三个不同的品种。数据集中含有178个样本&#xff0c;分别属于三个已知品种&#xff0c;每个样本…

移动App测试实战—专项测试

移动App测试实战—专项测试 我们在进行了手工的功能测试之后&#xff0c;也开发了一些自动化测试用例&#xff0c;并且做了性能测试之后&#xff0c;测试工作看似比较完整了。但是当我们的App在大量的用户那里被安装和使用的时候&#xff0c;还是会有很多我们之前没有预料的问题…

微服务+springcloud+springcloud alibaba学习笔记【Hystrix(豪猪哥)的使用】(6/9)

Hystrix&#xff08;豪猪哥&#xff09;的使用 6/91、Hystrix熔断器概述2、HyStrix重要概念3、hystrix案例3.1 新建模块 Cloud-provider-hystrix-payment80013.2 创建带降级的order模块 Cloud-comsumer-feign-hystrix-order803.3 配置服务降级:3.3.1 服务降级 Cloud-provider-h…

3年功能测试无情被裁,3个月学习自动化测试重新开始........

前言 不知不觉在软件测试行业工作了3年之久&#xff0c;虽然说我是主做的功能测试&#xff0c;但是我也一直是兢兢业业的呀&#xff0c;不曾想去年7月份无情被辞的消息让我感到一阵沉重。我曾经一直坚信自己的技能和经验足以支撑我在这个领域的未来&#xff0c;但现实却告诉我&…

日撸 Java 三百行day31

文章目录day31 整数矩阵及其运算面向对象思想java异常处理java中的getter和setter方法代码day31 整数矩阵及其运算 面向对象思想 结合之前day7和day8面向过程开发&#xff0c;只关注了矩阵加法和矩阵乘法的功能。而day31是面向对象开发&#xff0c;一个矩阵类&#xff0c;在这…

傅盛“追风”GPT,猎户星空春天来了?

GPT的横空出世&#xff0c;让冷清已久的商用服务机器人市场&#xff0c;又有了“新故事”。 从技术底层逻辑而言&#xff0c;服务机器人受到这类新技术的影响会更为明显。因为抛开硬件&#xff0c;服务机器人的内核其实就是AI&#xff0c;GPT大模型的出现显然成了现阶段该产业进…

KDSL-82轻型升流器

一、产品概述 KDSL-82 1000A大电流发生器是一种作为检验用的电流源&#xff0c;大电流试验器采用ARM芯片控制输出工艺和大容量的环形变压器&#xff0c;并且配有液晶屏显示的表计&#xff0c;同时显示一、二次电流、变比和秒表接点(或电位)的动作时间。外配铝合金机箱&#xff…

Mybatis核心

文章目录前言一、Configuration二、MappedStatement三、SqlSession四、Executor五、StatementHandler六、ParameterHandler七、ResultSetHandler八、TypeHandler总结前言 SqlSession是MyBatis提供的面向用户的操作数据库API。那么MyBatis底层是如何工作的呢&#xff1f;为了解…

SpringCloud-Gateway实现网关

网关作为流量的入口&#xff0c;常用的功能包括路由转发、权限校验、限流等Spring Cloud 是Spring官方推出的第二代网关框架&#xff0c;由WebFluxNettyReactor实现的响应式的API网关&#xff0c;它不能在传统的servlet容器工作&#xff0c;也不能构建war包。基于Filter的方式提…

​破除“内卷”,什么才是高阶智能座舱更优方案?

下一代智能座舱雏形已现。 从多屏互动到舱内全场景交互&#xff0c;从中控娱乐快速延伸到更多元化的车内娱乐平台&#xff1b;越来越多元化功能集中上车&#xff0c;座舱空间的营造&#xff08;包括氛围灯、香氛等&#xff09;以及AR技术的应用等等&#xff0c;开始深刻影响着…

关于ROS机器人-文心一言和CatGPT怎么看-

交流截图&#xff1a; 文字版本如下&#xff08;W-文心&#xff1b;C-猿如意&#xff09;&#xff1a; 如何通过蓝桥云课学习ROS机器人&#xff1f; W&#xff1a; 如果你想通过蓝桥云课学习ROS机器人&#xff0c;可以按照以下步骤进行&#xff1a; 确认ROS机器人的版本和教…