netty - ThreadDeathWatcher用法测试

Java中的线程终止问题:java.lang.ThreadDeath 综上所述,ThreadDeath异常是由Thread.stop()方法引发的,它可能导致线程在不安全的状态下停止执行。为了避免ThreadDeath异常的发生,应该避免使用Thread.stop()方法,而是使用共享变量或Thread.interrupt()方法来控制线程的终止。线程的执行逻辑在run()方法中实现,通过检查running变量的值来控制线程的执行。在上面的示例中,线程的执行逻辑在run()方法中实现,通过检查Thread.interrupted()方法的返回值来控制线程的执行。 阅读详情

测试代码如下



/**
 * Created by lihong10 on 2017/6/16.
 */
public class ThreadDeathWatcherTest {


    /**
     *
     该方法运行结果如下,并且控制台输出以下三行内容的顺序永远不变。
     main thread done
     the watched thread is alive ? : false
     the watched thread is dead, so , I can run !

     */
    public static void main(String[] args) throws InterruptedException {


        //获取主线程
        Thread main = Thread.currentThread();

        //创建一个主线程结束后才会开始运行的任务
        Runnable delayedTask = new TestRunnable(main);

        //ThreadDeathWatcher是netty的util包下的一个工具类,
        // watch方法的第一个参数可以认为是提交线程,只有提交线程运行结束,
        //第二个参数代表的Runnable任务才会开始执行
        //这个类是ReferenceCountUtil的public static <T> T releaseLater(T msg) 方法
        //实现的关键
        ThreadDeathWatcher.watch(main, delayedTask);

        //只有当前线程main线程运行结束,TestRunnable中的run方法才开始运行
        Thread.currentThread().sleep(1000);

        System.out.println("main thread done ");

    }


    private static class TestRunnable implements Runnable {
       private Thread thread;

        public TestRunnable(Thread thread) {
            this.thread = thread;
        }


        @Override
        public void run() {

            System.out.println("the watched thread is alive ? : " + thread.isAlive());

            System.out.println("the watched thread is dead, so , I can run !");
        }
    }

}

ThreadDeathWatcher 源码如下,本人增加了一行,将其内部的监视线程设置为非守护线程:

/*
 * Copyright 2014 The Netty Project
 *
 * The Netty Project licenses this file to you under the Apache License,
 * version 2.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at:
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */

import io.netty.util.concurrent.DefaultThreadFactory;
import io.netty.util.internal.StringUtil;
import io.netty.util.internal.SystemPropertyUtil;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;

import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * Checks if a thread is alive periodically and runs a task when a thread dies.
 * <p>
 * This thread starts a daemon thread to check the state of the threads being watched and to invoke their
 * associated {@link Runnable}s.  When there is no thread to watch (i.e. all threads are dead), the daemon thread
 * will terminate itself, and a new daemon thread will be started again when a new watch is added.
 * </p>
 */
public final class ThreadDeathWatcher {

    private static final InternalLogger logger = InternalLoggerFactory.getInstance(ThreadDeathWatcher.class);
    // visible for testing
    static final ThreadFactory threadFactory;

    // Use a MPMC queue as we may end up checking isEmpty() from multiple threads which may not be allowed to do
    // concurrently depending on the implemenation of it in a MPSC queue.
    private static final Queue<Entry> pendingEntries = new ConcurrentLinkedQueue<Entry>();
    private static final Watcher watcher = new Watcher();
    private static final AtomicBoolean started = new AtomicBoolean();
    private static volatile Thread watcherThread;

    static {
        String poolName = "threadDeathWatcher";
        String serviceThreadPrefix = SystemPropertyUtil.get("io.netty.serviceThreadPrefix");
        if (!StringUtil.isNullOrEmpty(serviceThreadPrefix)) {
            poolName = serviceThreadPrefix + poolName;
        }
        // because the ThreadDeathWatcher is a singleton, tasks submitted to it can come from arbitrary threads and
        // this can trigger the creation of a thread from arbitrary thread groups; for this reason, the thread factory
        // must not be sticky about its thread group
        threadFactory = new DefaultThreadFactory(poolName, true, Thread.MIN_PRIORITY, null);
    }

    /**
     * Schedules the specified {@code task} to run when the specified {@code thread} dies.
     *
     * @param thread the {@link Thread} to watch
     * @param task the {@link Runnable} to run when the {@code thread} dies
     *
     * @throws IllegalArgumentException if the specified {@code thread} is not alive
     */
    public static void watch(Thread thread, Runnable task) {
        if (thread == null) {
            throw new NullPointerException("thread");
        }
        if (task == null) {
            throw new NullPointerException("task");
        }
        if (!thread.isAlive()) {
            throw new IllegalArgumentException("thread must be alive.");
        }

        schedule(thread, task, true);
    }

    /**
     * Cancels the task scheduled via {@link #watch(Thread, Runnable)}.
     */
    public static void unwatch(Thread thread, Runnable task) {
        if (thread == null) {
            throw new NullPointerException("thread");
        }
        if (task == null) {
            throw new NullPointerException("task");
        }

        schedule(thread, task, false);
    }

    private static void schedule(Thread thread, Runnable task, boolean isWatch) {
        pendingEntries.add(new Entry(thread, task, isWatch));

        if (started.compareAndSet(false, true)) {
            Thread watcherThread = threadFactory.newThread(watcher);

            ///////////////////////////////////////////////////////////////////////

            watcherThread.setDaemon(false); ////////本人在源码中添加了这行代码,用以保证即使main线程结束,watch线程也能继续运行

            ///////////////////////////////////////////////////////////////////////

            watcherThread.start();
            ThreadDeathWatcher.watcherThread = watcherThread;
        }
    }

    /**
     * Waits until the thread of this watcher has no threads to watch and terminates itself.
     * Because a new watcher thread will be started again on {@link #watch(Thread, Runnable)},
     * this operation is only useful when you want to ensure that the watcher thread is terminated
     * <strong>after</strong> your application is shut down and there's no chance of calling
     * {@link #watch(Thread, Runnable)} afterwards.
     *
     * @return {@code true} if and only if the watcher thread has been terminated
     */
    public static boolean awaitInactivity(long timeout, TimeUnit unit) throws InterruptedException {
        if (unit == null) {
            throw new NullPointerException("unit");
        }

        Thread watcherThread = ThreadDeathWatcher.watcherThread;
        if (watcherThread != null) {
            watcherThread.join(unit.toMillis(timeout));
            return !watcherThread.isAlive();
        } else {
            return true;
        }
    }

    private ThreadDeathWatcher() { }

    private static final class Watcher implements Runnable {

        private final List<Entry> watchees = new ArrayList<Entry>();

        @Override
        public void run() {
            for (;;) {
                fetchWatchees();
                notifyWatchees();

                // Try once again just in case notifyWatchees() triggered watch() or unwatch().
                fetchWatchees();
                notifyWatchees();

                try {
                    Thread.sleep(1000);
                } catch (InterruptedException ignore) {
                    // Ignore the interrupt; do not terminate until all tasks are run.
                }

                if (watchees.isEmpty() && pendingEntries.isEmpty()) {

                    // Mark the current worker thread as stopped.
                    // The following CAS must always success and must be uncontended,
                    // because only one watcher thread should be running at the same time.
                    boolean stopped = started.compareAndSet(true, false);
                    assert stopped;

                    // Check if there are pending entries added by watch() while we do CAS above.
                    if (pendingEntries.isEmpty()) {
                        // A) watch() was not invoked and thus there's nothing to handle
                        //    -> safe to terminate because there's nothing left to do
                        // B) a new watcher thread started and handled them all
                        //    -> safe to terminate the new watcher thread will take care the rest
                        break;
                    }

                    // There are pending entries again, added by watch()
                    if (!started.compareAndSet(false, true)) {
                        // watch() started a new watcher thread and set 'started' to true.
                        // -> terminate this thread so that the new watcher reads from pendingEntries exclusively.
                        break;
                    }

                    // watch() added an entry, but this worker was faster to set 'started' to true.
                    // i.e. a new watcher thread was not started
                    // -> keep this thread alive to handle the newly added entries.
                }
            }
        }

        private void fetchWatchees() {
            for (;;) {
                Entry e = pendingEntries.poll();
                if (e == null) {
                    break;
                }

                if (e.isWatch) {
                    watchees.add(e);
                } else {
                    watchees.remove(e);
                }
            }
        }

        private void notifyWatchees() {
            List<Entry> watchees = this.watchees;
            for (int i = 0; i < watchees.size();) {
                Entry e = watchees.get(i);
                if (!e.thread.isAlive()) {
                    watchees.remove(i);
                    try {
                        e.task.run();
                    } catch (Throwable t) {
                        logger.warn("Thread death watcher task raised an exception:", t);
                    }
                } else {
                    i ++;
                }
            }
        }
    }

    private static final class Entry {
        final Thread thread;
        final Runnable task;
        final boolean isWatch;

        Entry(Thread thread, Runnable task, boolean isWatch) {
            this.thread = thread;
            this.task = task;
            this.isWatch = isWatch;
        }

        @Override
        public int hashCode() {
            return thread.hashCode() ^ task.hashCode();
        }

        @Override
        public boolean equals(Object obj) {
            if (obj == this) {
                return true;
            }

            if (!(obj instanceof Entry)) {
                return false;
            }

            Entry that = (Entry) obj;
            return thread == that.thread && task == that.task;
        }
    }
}
SKILL实现电路virtuoso原理图schematic中引脚pin的net自动打上pin label 阅读详情

相关推荐

PID控制器(位置式和增量式)

PID控制算法

zhinian_hao的博客 4512

池化技术 java_netty4的内存池化技术

此文已由作者徐赟授权网易云社区发布。欢迎访问网易云社区,了解更多网易技术产品运营经验。一、 前言java语言在运行于JVM的前提下,内存分配和回收通常无需用户干预。用户创建对象时,系统会在堆中分配空间存放对象,如果堆空间不足就触发JVM的gc做内存回收,在删除无效对象的同时对堆空间做整理,清除内存碎片使空闲内存连续,用于支持大对象的分配。脏活累活都让JVM干了,用户只要专注自己的逻辑,java应用...

weixin_29332623的博客 597

python——模拟砍价

类型:随机数。

m0_62488776的博客 1972

Netty内存分配---线程缓存分配

cache

xiaoxishuaidaile的博客 604

基于CLICKHOUSE的数据仓库分层规范

接入层。

zjyy1987的博客 771

JAVA:Spring Boot 集成 Baidu UID-Generator ID 生成器

百度UID-Generator是一款高性能分布式ID生成器,支持600万QPS,提供Snowflake扩展版和Cache模式两种实现方式。文章详细介绍了如何在Spring Boot项目中集成该组件,包括Maven依赖配置、MySQL表结构初始化、Spring Boot数据源配置、WorkerId分配策略实现以及UID生成器的核心配置。该方案具有无中心依赖、ID单调递增、支持集群部署等特点,适用于订单号、用户ID等分布式场景。通过缓存模式(Cache-Buffer)可进一步提升性能,满足高并发业务需求。

木头 487

Java基础之《netty(20)—netty心跳机制》

1、编写一个netty心跳检测机制案例,当服务器超过3秒没有读时,就提示读空闲。3、当服务器超过7秒没有读或者写操作时,就提示读写空闲。2、当服务器超过5秒没有写操作时,就提示写空闲。

csj50的专栏 989

华为OD机考双机位C卷 - 简单的解压缩算法 (Java & Python & JS & GO & C++ & C)

华为OD机考双机位C卷 - 简单的解压缩算法 , 提供Java、C++、Python、Go、JavaScript源码实现,并提供完整思路讲解,以及在线OJ模拟做题。

算法大师! 130

对线程、进程、多线程的理解使用和产生死锁

线程、进程、多线程1.继承Thread类1.1 继承操作有3步2.Runnable接口2.1 继承操作有3步3.Callable接口(了解)初识并发问题流程图线程停止线程休眠sleep线程礼让 yield,礼让不一定成功线程强制执行 Join(插队)线程优先级守护线程(GC 日志 监控内存)daemon线程同步 synchronized同步方法同步块 synchronized(obj){}JUC安全类型集合产生死锁四个条件lock锁(可重复锁)生产者消费者问题管程法 及时不创建线程,也会有main线程,GC

jj89929665的博客 355

用 ABAP ADK 写一个可控的自建表归档程序:从选择屏幕到 ARCHIVE_SAVE_OBJECT 的完整链路

文章摘要: 本文介绍了SAP系统中数据归档的核心概念与实践方法。归档旨在将不常访问但需保留的数据从在线数据库移出,以减轻系统负载,同时满足合规要求。文章重点阐述了: 归档与备份、重组的本质区别 SAP归档框架的核心组件:归档对象(AOBJ)、归档管理界面(SARA)和ADK开发工具包 通过YAPTMAIN表示例,展示了完整的归档流程: 使用选择屏幕控制归档范围 管理归档会话 写入归档记录 生成统计报表 强调了归档程序设计中需要考虑的运维、审计和性能因素 该方案可有效解决自建日志表"悄悄长胖&quo

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 232

win7 vs2012+wdk8.0 搭建wdf驱动开发环境

开发环境搭建: 系统:win7 x64 工具:vs2012 + WDK8.0 插件:wdfcoinstaller.msi (1)先安装vs2012,再安装wdk8.0,这样在打开vs2012时可以创建windows drivers类型的工程。 注:vs2012不能安装wdk8.1,wdk8.1必须安装在vs2013上 下载链接:http://msdn.microsoft.com/zh-cn/win...

技术联盟 5344

netty实现与智能手表通信对接

最近在做java服务端通过netty与手表通信,基于GPRS通信协议,可实现接收手表的信息,也可由服务端主动向手表发送信息。 服务端 @Component public class NettyServer { /** * 日志 */ private Logger log = LoggerFactory.getLogger(getClass()); /** * IP地址 */ @Value("${netty.ip}") priv

我的博客 2155

STEP 7-Micro/WIN SMART 编程软件:从入门到精通的使用指南

通过不断实践,熟悉软件的各项功能和操作技巧,工程师可更好地应对工业自动化控制中的各种挑战,开发出高效、稳定的控制程序。项目的基本组件是构成程序的核心元素,包括:程序块(主程序 OB1、子程序和中断程序)、数据块(给 V 存储器赋初值)、系统块(硬件组态和参数设置)、符号表(用符号代替存储器地址,使程序更易理解)以及状态图表(监视、修改和强制变量状态)。下载程序时,单击工具栏上的 “下载” 按钮,在弹出的下载对话框中选择要下载的块(程序块、数据块、系统块),单击 “下载” 即可。

电工 5575

Thread.stop() 与 ThreadDeath 的理解、注意点以及误区

Thread.stop() 与 ThreadDeath 的理解、注意点以及误区

赵丙双的博客 1272

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

Java终止线程的方法

Java终止线程的方法 1. Thread实例对象的stop()方法 该方法让线程抛出Error的子异常ThreadDeath异常来暴力终止线程,ThreadDeath继承于Error。 如果想要调用stop方法又想要料理线程后事,可以在run方法代码块中捕获ThreadDeath或Error或Throwable异常,在catch方法中处理后事。 注意在catch中考虑重新抛出异常来终止线程,不这样做视情况可能会变成线程救援(如在循环中捕获并处理)。 线程救援示例: class TimeThread ext

qq309648008的博客 435

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

java.lang.ThreadDeath: 线程终止的正确解决方法,亲测有效,嘿嘿嘿

当你看到`ThreadDeath`这个错误时,这通常表示有两种可能性: 1. 你的代码或你使用的某个库直接调用了`Thread.stop()`方法,尽管该方法已被废弃。 2. JVM内部在处理某些情况(如垃圾收集或类加载)时,可能抛出了这个错误。但在实际应用中,这种情况较少见。 ### 报错原因 报错的主要原因是直接调用了`Thread.stop()`方法。这个方法被废弃是因为它可能导致线程在不安全的状态下停止,比如正在处理共享资源或持有锁时。这可能导致数据不一致和其他并发问题。

PythonAigc的博客 788

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

netty5学习笔记-内存池5-PoolThreadCache

看了前面的PoolArena分析,我们知道PoolArena在分配内存时,使用了synchronized来保证线程安全,这样就带来了一定的效率问题。如何能再此基础上再优化呢,答案很简单,使用ThreadLocal类似的解决方案避免加锁! 为什么可以使用ThreadLocal,如果了解过netty线程模型(有兴趣后续可以一起学习),应该知道netty的woker线程池,它负责了数据的接收、发送(编解

youaremoon的专栏 4180

如何解决 java.lang.ThreadDeath: 线程终止问题?亲测有效的解决方法!

是一个用于表示线程被终止的异常,它通常由 Java 的方法引发。是一个Error类型的异常,它通常不会被应用程序捕获或处理,而是表明线程正在被强制终止。一般来说,不应该直接抛出或捕获,因为它的设计目的就是标识线程终止的过程。

猿鹏探码的博客 1555

Thread类相关方法

Thread各状态 线程某时间点只能处于一种状态。这些状态是虚拟机状态,与操作系统线程状态无关。 NEW:线程尚未启动的状态,调用start之前 RUNNABLE:可运行、就绪状态,表示已经在JVM中执行,但是同一时间只有一线程获取到CPU资源,所以虽然在JVM层面多个线程一直处理RUNNABLE状态,但是在操作系统层面并不是真正得到CPU资源运行 BLOCKED:线程因为等待monitor锁而...

1032851561的博客 7135

死磕Netty源码之内存分配详解(三)PoolThreadCache线程缓存内存分配

内存分配 关于我:http://huangth.com GitHub地址:https://github.com/RobertoHuang 免责声明:本系列博客并非原创,主要借鉴和抄袭闪电侠,占小狼等知名博主博客。如有侵权请及时联系 线程私有分配 在介绍PoolArena内存分配结构分析的时候提到内存分配会先从线程缓存里分配,这个线程缓存其实就是PoolThre...

黄太洪的博客 2481

蹊跷的ThreadDeath,令人郁闷的glassfish

上周遇到的一个bug,ThreadDeath error,从而导致系统的每个请求都失败。能够让系统的每个traffic请求都失败的bug,这个严重程度不言而喻。看看是怎么回事吧? 其实问题的表现很简单:在请求处理过程中,抛出了一个ThreadDeath 的error: Caused by: java.lang.ThreadDeath at org.apache.catalina.

u013890660的专栏 4505

ThreadDeath 理解

1 public class RunnableTest2 { 2 public static Object obj1 = new Object(); 3 public static Object obj2 = new Object(); 4 private MyThread1 t1 = new MyThread1(); 5 private My...

weixin_30729609的博客 737

线程死亡的监控与回调

//监控线程是否死亡 package io.mycat.bigmem.util; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicBoolean;

w329636271的专栏 2712

PoolThreadCache

概述(Motivation) 如果说netty维护了一个总的内存缓冲池,那么这个就是线程自己的内存缓冲池,它的工作大致是线程从“总池”获得的内存用完并不直接还回去,而是暂放到自己的内存缓冲池中。 实现细节(Modification) 主要成员变量 private static final InternalLogger logger = InternalLoggerFactory.getInstan...

weixin_30642267的博客 219

Coroutine in Java - Quasar Fiber实现

20160827更新补充method instrument实现细节(怎么找到suspend call、switch case织入实现、suspend call在try catch块中,如何处理、什么情况下在suspend call前后可以不织入也能正常运行) 简介 说到协程(Coroutine),很多人会想到go,lua,erlang等语...

weixin_34124651的博客 495
上一篇: netty-AbstractReferenceCounted用法测试例子
下一篇: 一个线程安全的计数器实现(java),可以让一个变量每天从1开始递增
lhever_
博客等级 码龄14年 213粉丝 130原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值