Java实现双保险线程

双保险线程,每次启动2个相同的线程,互相检测,避免线程死锁造成影响。
两个线程都运行,但只有一个线程执行业务,但都会检测对方的时间戳 如果时间戳超过休眠时间3倍没有更新的话,则重新启动对方线程。
例子:
一般工作线程由自己实现,继承DoubleInsuredThead,在run2()方法里实现具体需求,和一般线程的run()方法不同,run2()
里不用处理循环和休眠 检测线程已经由CheckThread实现,可以直接使用,如:启动用户检测线程。
public static void startMonitor() {
	System.out.println("启动用户会话检测线程");
	UserMonitor worker = new UserMonitor("WT-UserMonitor");
	CheckThread checker = new CheckThread("WT-UserMonitorCheck",userMonitorIntevalTime);
	DoubleInsuredThead.startDoubleInsuredThead(worker, checker);
}

完整代码:

package com.yx.demo.thread;

/**
 * DoubleInsuredThead
 * 双保险线程,每次启动2个相同的线程,互相检测,避免线程死锁造成影响。
 * <p>
 * 两个线程都运行,但只有一个线程执行业务,但都会检测对方的时间戳 如果时间戳超过休眠时间3倍没有更新的话,则重新启动对方线程
 * <p>
 * 代码例子:
 * 一般工作线程由自己实现,继承DoubleInsuredThead,在run2()方法里实现具体需求,和一般线程的run()方法不同,run2()
 * 里不用处理循环和休眠 检测线程已经由CheckThread实现,可以直接使用
 *
 * <pre>
 *  	启动用户检测线程
 *  	public static void startMonitor() {
 *  		System.out.println("启动用户会话检测线程");
 *  		UserMonitor worker = new UserMonitor("XX-UserMonitor");
 *  		CheckThread checker = new CheckThread("XX-UserMonitorCheck",userMonitorIntevalTime);
 *  		DoubleInsuredThead.startDoubleInsuredThead(worker, checker);
 *        }
 *  </pre>
 *
 * @author yx
 * @date 2019/12/21 0:36
 */
public abstract class DoubleInsuredThead extends Thread {

    /**
     * 默认线程休眠时间为1000毫秒
     */
    public static final long DEFAULT_SLEEP_TIME = 1000;

    /**
     * 是否运行本线程
     */
    private boolean running = true;
    /**
     * 线程时间戳,每次run的时候更新
     */
    private long timeStamp = System.currentTimeMillis();
    /**
     * 互相检测的另外一个线程
     */
    DoubleInsuredThead another;

    public DoubleInsuredThead(String name) {
        super(name);
    }

    /**
     * 子线程的执行业务的方法,相当于Runnable.run()方法
     */
    public abstract void run2();

    /**
     * 获得实例,重启线程的时候用
     *
     * @return
     */
    public abstract DoubleInsuredThead newInstance();

    /**
     * 启动工作线程,使用默认检测线程
     *
     * @param workerThread
     */
    public static void startDoubleInsuredThead(DoubleInsuredThead workerThread) {
        CheckThread checkerThread =
                new CheckThread(workerThread.getName() + "-checker", workerThread.getSleepTime());
        workerThread.another = checkerThread;
        checkerThread.another = workerThread;
        workerThread.start();
        checkerThread.start();
    }

    /**
     * 自定义检测线程的方式启动工作线程,建议使用startDoubleInsuredThead(DoubleInsuredThead workerThread)
     *
     * @param worker  工作线程
     * @param checker 检测线程
     * @deprecated
     */
    public static void startDoubleInsuredThead(DoubleInsuredThead worker,
            DoubleInsuredThead checker) {
        worker.another = checker;
        checker.another = worker;
        worker.start();
        checker.start();
    }

    /**
     * 重启线程
     */
    public void restart() {
        System.out.println("线程\"" + getName() + "\"重新启动了");
        // 停止当前线程
        running = false;
        // 启动新线程
        DoubleInsuredThead t = newInstance();
        t.setTimeStamp(System.currentTimeMillis());
        another.another = t;
        t.another = another;
        t.start();
    }

    @Override
    public void run() {
        while (running) {
            // 执行子类线程的业务
            run2();
            checkAnother();
            setTimeStamp(System.currentTimeMillis());

            try {
                Thread.sleep(getSleepTime());
            } catch (InterruptedException e) {
                e.printStackTrace();
                System.out.println("线程休眠出错:" + e.getMessage());
            }
        }
    }

    /**
     * 获得线程休眠的时间,单位毫秒
     *
     * @return
     */
    public long getSleepTime() {
        return DEFAULT_SLEEP_TIME;
    }

    /**
     * 对另外一个线程进行检测
     */
    private void checkAnother() {
        if (another.isTimeout()) {
            another.restart();
        }
    }

    /**
     * 是否更新时间戳超时
     *
     * @return
     */
    private boolean isTimeout() {
        System.out.println("timeStamp = " + getTimeStamp());
        return System.currentTimeMillis() - getTimeStamp() > getSleepTime() * 3;
    }

    /**
     * @param timeStamp the timeStamp to set
     */
    public void setTimeStamp(long timeStamp) {
        this.timeStamp = timeStamp;
    }

    /**
     * @return the timeStamp
     */
    public long getTimeStamp() {
        return timeStamp;
    }

}

检测线程:

package com.yx.demo.thread;

/**
 * CheckThread
 * 双保险线程里专门用来检测的线程
 *
 * @author yx
 * @date 2019/12/21 0:38
 */
public class CheckThread extends DoubleInsuredThead {

    /**
     * 检测休眠时间,默认1秒
     */
    private long checkIntevalTime = 1000;

    public CheckThread(String name, long checkTime) {
        super(name);
        this.checkIntevalTime = checkTime;
    }

    @Override
    public DoubleInsuredThead newInstance() {
        return new CheckThread(getName(), checkIntevalTime);
    }

    @Override
    public void run2() {
        // 只打印信息
        System.out.println("线程" + getName() + "完成了工作");
    }

    @Override
    public long getSleepTime() {
        return checkIntevalTime;
    }

    /**
     * 测试代码
     *
     * @param args
     */
    public static void main(String[] args) {
        CheckThread worker = new CheckThread("worker", 3000);
        DoubleInsuredThead.startDoubleInsuredThead(worker);
    }
}

发布了142 篇原创文章 · 获赞 258 · 访问量 16万+

猜你喜欢

转载自blog.csdn.net/conconbenben/article/details/103640228