Tap*_*ose 5 java multithreading
我Thread从ServletContextListener初始化上下文开始,并在上下文被销毁时尝试停止它.这堂课是:
public enum BlinkLedTask {
INSTANCE;
private Logger logger = RpiLogger.getLogger(getClass());
private Task task;
private ExecutorService service;
private BlinkLedTask() {
}
public void run(String[] frequency) {
stop();
task = new Task(frequency);
service = Executors.newSingleThreadExecutor(RpiThreadFactory.INSTANCE);
service.execute(task);
}
public void stop() {
if(Objects.isNull(task) || Objects.isNull(service)) {
return;
}
try {
task.terminate();
service.shutdownNow();
} catch (Exception cause) {
logger.error(cause.getMessage(), cause);
}
}
private static class Task implements Runnable {
private volatile boolean running = true;
private String[] frequency;
private volatile Logger logger = RpiLogger.getLogger(getClass());
private Task(String[] frequency) {
this.frequency = frequency;
}
@Override
public void run() {
while(running && !Thread.interrupted()) {
try {
resetLed();
blinkLed();
} catch (Throwable cause) {
logger.error(cause.getMessage(), cause);
running = false;
try {
resetLed();
} catch (Throwable ignore) {
}
}
}
}
private void resetLed() throws Exception {
executeScript(Script.BLINK_LED_RESET);
}
private void blinkLed() throws Exception {
executeScript(Script.BLINK_LED, new String[]{frequency[0], frequency[1], frequency[2]});
}
private void executeScript(Script script, String... args) {
ScriptExecutor scriptExecutor = new ScriptExecutor(ScriptExecutor.BASH, script);
scriptExecutor.execute(true, args);
}
private void terminate() {
logger.info("Stopping - " + Thread.currentThread().getName());
running = false;
}
}
}
Run Code Online (Sandbox Code Playgroud)
这个Singleton和它运行一个shell脚本,直到它停止.可以从任何地方调用此类,因此在创建新脚本之前,如果当前正在执行shell脚本,我需要停止该线程Thread.
出于测试目的,我在run()初始化上下文时执行了此类的方法,并stop()在销毁时调用.
我删除代码后重新部署了war文件run(),我原以为stop()会终止task,但事实并非如此.
我也尝试了不同的实施run()和stop():
public void run(String[] frequency) {
stop();
task = new Task(frequency);
Thread thread = RpiThreadFactory.INSTANCE.newThread(task);
tasks.add(ImmutablePair.of(thread, task));
thread.start();
}
public void stop() {
for(ImmutablePair<Thread, Task> pair : tasks) {
try {
pair.right.terminate();
pair.left.join();
} catch (Exception ex) {
}
}
}
Run Code Online (Sandbox Code Playgroud)
这里tasks是private ArrayList<ImmutablePair<Thread, Task>> tasks = new ArrayList<ImmutablePair<Thread,Task>>();.本ImmutablePair属于公共资源,lang3.但我收到java.util.ConcurrentModificationException了增强的for循环的迭代.我不知道的原因.
当服务器关闭时,stop()它正在按预期工作.我正在使用Jetty.
RpiThreadFactory:
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.log4j.Logger;
import com.edfx.rpi.app.utils.logger.RpiLogger;
public enum RpiThreadFactory implements ThreadFactory {
INSTANCE;
private final AtomicInteger poolNumber = new AtomicInteger(1);
private final Logger logger = RpiLogger.getLogger(getClass());
private final ThreadGroup threadGroup;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;
private RpiThreadFactory() {
SecurityManager securityManager = System.getSecurityManager();
threadGroup = (securityManager != null) ? securityManager.getThreadGroup() : Thread.currentThread().getThreadGroup();
namePrefix = "RpiPool-" + poolNumber.getAndIncrement() + "-Thread-";
}
public Thread newThread(Runnable runnable) {
Thread thread = new Thread(threadGroup, runnable, namePrefix + threadNumber.getAndIncrement(), 0);
thread.setPriority(Thread.NORM_PRIORITY);
thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
public void uncaughtException(Thread thread, Throwable cause) {
logger.error(cause.getMessage(), cause);
}
});
return thread;
}
}
Run Code Online (Sandbox Code Playgroud)
ScriptExecutor:
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import com.edfx.rpi.app.utils.logger.RpiLogger;
public class ScriptExecutor {
private static final Logger LOGGER = RpiLogger.getLogger(ScriptExecutor.class);
public static final String BASH = "/bin/bash";
private Script script;
private Process process;
private String output;
private int exitValue;
public ScriptExecutor(Script script) {
this.script = script;
}
public void execute(boolean destroyProcess, String... args) throws ScriptNotExistException {
if(!script.exists()) {
throw new ScriptNotExistException(script.getScriptName() + " does not exists.");
}
try {
List<String> commands = new ArrayList<>();
commands.add(BASH);
commands.add(script.getAbsoultePath());
if(Objects.nonNull(args)) {
commands.addAll(Arrays.asList(args));
}
StringBuilder builder = new StringBuilder("Executing script: ");
builder.append(script.getScriptName());
if(Objects.nonNull(args) && args.length > 0) {
builder.append(" with parameters: ");
builder.append(StringUtils.join(args, " "));
}
LOGGER.info(builder.toString());
ProcessBuilder processBuilder = new ProcessBuilder(commands.toArray(new String[commands.size()]));
process = processBuilder.start();
StringBuilder outputBuilder = new StringBuilder();
InputStream inputStream = process.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String line = StringUtils.EMPTY;
while ((line = bufferedReader.readLine()) != null) {
outputBuilder.append(line);
outputBuilder.append("\n");
}
process.waitFor();
exitValue = process.exitValue();
LOGGER.info("Process for: " + script.getScriptName() + " is executed. Exit value: " + exitValue);
if(destroyProcess) {
destroyProcess();
}
output = outputBuilder.toString();
} catch (Exception cause) {
throw new ScriptExecutionException(cause);
}
}
public String getOutput() {
return output;
}
public int getExitValue() {
return exitValue;
}
public void destroyProcess() {
if(Objects.nonNull(process)) {
LOGGER.info("Process for: " + script.getScriptName() + " is destroyed.");
process.destroy();
}
}
}
Run Code Online (Sandbox Code Playgroud)
这是在Jetty Web容器中运行的Web应用程序.服务器安装在启用嵌入式硬件java中.这个硬件如何连接LED.应用程序接受外部请求,可以是REST并启动LED.因此LED可以根据任何请求开始闪烁; 但它一次只能提供一个请求.
这就是为什么我有stop停止以前运行的过程,如果有的话.stop正常情况下的作品.
但我看到,虽然LED闪烁,我在不停止服务器的情况下进行部署,但运行的线程不会停止.如果我停止服务器并进行部署并再次启动,则此时正在运行的线程将被终止.
线程循环while并执行Process到本机.这Process是一次性工作,所以这Process不会让线程被杀死.
为了重现我所做的问题,我在初始化上下文时创建了线程,并在它被销毁时尝试杀死它.现在,如果我写了一些东西,contextDestroyed我可以看到它们被执行了.
我不明白为什么在我重新部署时停止服务器杀死线程.
您应该对 processBuilder.start() 返回的 Process 实例调用 process.destroy()。实际上,您在调用 BlinkLedTask.terminate() 时所做的只是设置一些标志。此时您应该调用 process.destroy()。
下面我展示了一个如何重写它的示例。它不涉及您的 ScriptExecutor 类(当然您可以将逻辑移到那里并在调用眨眼Led()时将进程实例返回到 BlinkLedTask )。
这里的主要区别是,我将 Process 实例的引用保留在blinkLedProcess 字段中,并且当调用terminate() 时,我直接调用process.destroy() 来销毁进程。
您写道“当服务器关闭时,stop() 会按预期工作。我正在使用 Jetty。” 确实是的。这是因为通过调用processBuilder.start();您可以创建主码头进程的子进程。当你杀死jetty时,它的所有子进程也会被杀死。如果你不杀死jetty,你需要通过调用destroy()方法手动杀死子进程。
它应该是这样的:
public enum BlinkLedTask {
(...)
private Process resetLedProcess;
private Process blinkLedProcess;
(...)
private void blinkLed() throws Exception {
String[] args = new String[] { frequency[0], frequency[1], frequency[2] };
List<String> commands = new ArrayList<>();
//commands.add(BASH);
commands.add(script.getAbsoultePath());
if (Objects.nonNull(args)) {
commands.addAll(Arrays.asList(args));
}
StringBuilder builder = new StringBuilder("Executing script: ");
builder.append(script.getAbsoultePath());
if (Objects.nonNull(args) && (args.length > 0)) {
builder.append(" with parameters: ");
builder.append(StringUtils.join(args, " "));
}
ProcessBuilder processBuilder = new ProcessBuilder(commands.toArray(new String[commands.size()]));
blinkLedProcess = processBuilder.start();
StringBuilder outputBuilder = new StringBuilder();
InputStream inputStream = blinkLedProcess.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String line = StringUtils.EMPTY;
while ((line = bufferedReader.readLine()) != null) {
outputBuilder.append(line);
outputBuilder.append("\n");
}
blinkLedProcess.waitFor();
int exitValue = blinkLedProcess.exitValue();
System.out.println(
"Process for: " + Script.BLINK_LED.getAbsoultePath() + " is executed. Exit value: " + exitValue);
}
(...)
private void terminate() {
System.out.println("Stopping - " + Thread.currentThread().getName());
running = false;
if (resetLedProcess != null) {
resetLedProcess.destroy();
System.out.println("Destroyed reset process");
}
if (blinkLedProcess != null) {
blinkLedProcess.destroy();
System.out.println("Destroyed blink process");
}
}
(...)
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1199 次 |
| 最近记录: |