0. 一个简单的工作者线程实现
- 我认为在涉及多线程/并发编程时,如果没有丰富的经验,则极易出错。所以应当优先使用 JDK 中提供的并发编程类。
- 必须留心共享变量的竞态条件。可能一不小心便会造成死锁。多思考,多分析。且代码尽量简洁,控制共享变量的操作/使用范围。
1. 代码如下:
import java.util.concurrent.atomic.AtomicInteger;
public class Worker extends Thread {
private static final AtomicInteger counter = new AtomicInteger(1);
private volatile Runnable task;
private static final String NAME_PREFIX = "worker-";
private final String workerName;
private boolean isInterrupted = false;
private volatile boolean isRunning = false;
private volatile boolean isStarted = false;
private boolean isDestroyed = false;
public Worker(String name) {
this.workerName = NAME_PREFIX + counter.getAndIncrement() + (name == null ? "" : "-" + name);
}
public Worker() {
this(null);
}
public Worker(String name, Runnable task) {
this(name);
this.task = task;
}
public boolean doTask(Runnable task) {
if (task == null) {
throw new IllegalArgumentException("task must not be null.");
}
if (!isStarted && !isDestroyed) {
this.start();
}else if (isDestroyed) {
throw new IllegalStateException("this worker was destroyed.");
}
if (this.task != null) {
return false;
}
return compareAndUpdate(null, task);
}
private synchronized boolean compareAndUpdate(Runnable old, Runnable update) {
if (this.task == old) {
this.task = update;
if (this.task != null) {
this.notify();
}
return true;
}
return false;
}
public boolean isRunning() {
return this.isRunning;
}
public boolean isStarted() {
return this.isStarted;
}
public String getWorkerName() {
return workerName;
}
@Override
public void run() {
this.isStarted = true;
while(!isInterrupted) {
this.isRunning = true;
Runnable currentTask = task;
if (currentTask != null) {
currentTask.run();
compareAndUpdate(currentTask, null);
}else {
synchronized (this) {
try {
if (this.task != null) {
continue;
}else {
this.isRunning = false;
wait();
}
} catch (InterruptedException ignore) {
isInterrupted = true;
this.interrupt();
}
}
}
}
this.isStarted = false;
this.isDestroyed = true;
}
public void exit() {
this.isDestroyed = true;
this.isStarted = false;
this.interrupt();
System.out.println(getWorkerName() + " exited.");
}
}