All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.neko233.toolchain.actor.Worker Maven / Gradle / Ivy

package com.neko233.toolchain.actor;


import lombok.Getter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;


/**
 * worker 一直 running 运行某个功能
 */
@Slf4j
@Getter
@ToString
public class Worker implements Runnable {

    private static final WorkerTask STOP_SIGNAL = WorkerTask.shutdown();
    private final String workerType;
    private final int workerIndex;
    private final Thread thread;
    private volatile boolean isRunning;
    private volatile boolean forceStop;
    private final BlockingQueue taskQueue;


    public Worker(String workerType, int workerIndex, int queueLength) {
        this.workerType = workerType;
        this.workerIndex = workerIndex;
        String name = String.format("%s-%d", workerType, workerIndex);
        this.thread = new Thread(this, name);
        this.thread.setDaemon(false);
        this.taskQueue = new ArrayBlockingQueue<>(queueLength);
    }

    public void start() throws Throwable {
        this.isRunning = true;
        this.forceStop = false;
        this.thread.start();
    }

    public void sendStopSignal() {
        this.isRunning = false;

        for (int times = 0; times < 1000; times++) {
            if (this.taskQueue.offer(STOP_SIGNAL)) {
                return;
            }
        }

        log.error("[Worker] add stop signal failed. threadName={} taskQueueSize={}", thread.getName(), taskQueue.size());
    }

    public void waitShutdown(long globalStopMs, long awaitInterruptionTimeoutMS) {
        this.sendStopSignal();
        // 先等 waitTimeMS, 等其安全退出

        try {
            if (awaitInterruptionTimeoutMS <= 0) {
                this.thread.join();
            } else {
                long finishStopSpendMs = System.currentTimeMillis() - globalStopMs;
                long remainWaitTimeMS = awaitInterruptionTimeoutMS - finishStopSpendMs;
                if (remainWaitTimeMS > 0) {
                    this.thread.join(remainWaitTimeMS);
                }
            }
        } catch (InterruptedException e) {
        }

        // 如果线程还存活,则直接发起中断
        if (this.thread.isAlive()) {
            long finishStopSpendMs = System.currentTimeMillis() - globalStopMs;
            log.warn("[Worker] thread is still alive then we will interrupt it. threadName={} taskQueueSize={} escapedTimeMS={}",
                    thread.getName(), taskQueue.size(), finishStopSpendMs);
            this.forceStop = true;
            this.thread.interrupt();
            try {
                this.thread.join();
            } catch (InterruptedException e) {
            }
        }
    }

    public void addTask(WorkerTask workerTask) {
        boolean isOk = taskQueue.offer(workerTask);
        if (!isOk) {
            log.error("[Worker] task queue is full! Task:{}", workerTask.getType());
        }
    }

    @Override
    public void run() {
        WorkerTask workerTask;
        while (isRunning || !taskQueue.isEmpty()) {
            try {
                // 由于 offer shutdown signal 可能会失败
                workerTask = isRunning ? taskQueue.take() : taskQueue.poll();
                if (workerTask == null || workerTask == STOP_SIGNAL) {
                    continue;
                }
                Runnable runnable = workerTask.getTask();
                if (runnable == null) {
                    log.error("why workerTask type = {} runnable is null ?", workerTask.getType());
                    continue;
                }
                runnable.run();

            } catch (InterruptedException e) {
                if (isRunning) {// 减少日志污染
                    log.error("[Worker] do task error!", e);
                }
            } catch (Throwable t) {
                log.error("[Worker] do task error!", t);
            }
        }
    }


}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy