优化Java线程实现类
程序员文章站
2022-05-31 14:21:26
...
多线程编程一方面比较复杂,另一方面运行出错后,难以定位等,所以针对对多线程实现的场景需要更谨慎,多关注编程实现的细节, 以便更好的实现和问题定位。
我们先来看一段实现Thread线程类的代码:
public class ThreadTest {
public static void main(String[] args) {
new Thread() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(getName() + ", do something...");
}
}
}.start();
System.out.println("exit main...");
}
}
咋一看好像没什么问题,确实这段程序执行起来是没有什么大问题,但是仔细想一想程序是写给人看的,而且是由人维护的, 有更大的可能是你来实现,其他人来维护的,如果没问题还好,一旦有问题,再回过头来看代码和查找日志,都是个比较头疼的问题。
从代码维护角度来说,这段代码存在以下几个问题(当然不同的人理解不一样,有一些不见得是问题):
- 未定义变量和匿名实现,不利于对象的回收和利用
- 未设置为守护线程,主线程已停止,子线程还在后台执行
- 未定义结束标识,线程循环执时无法在流程上友好地停止循环
- 未设定明确的线程名,系统将自动分配线程名,然而在一个系统中往往会有很多个线程,如果都是这样,就无法确定哪个线程对应处理流程,特别是通过一些工具进行分析的时候,比如jconsole等
- 无明确的初始化,启动,结束日志,一旦线程任意环节出现问题,缺少必要的日志,都给问题定位带来困扰。 线程实现定周期执行,使用线程Thread.sleep(long millis),实际线程资源并没有释放,不利于资源利用,比较好的方法定义一个锁对象,通过Object.wait(long millis) 进行资源释放
为解决以上问题,对Thread类做二次开发,具体如下:
public abstract class AbstractCycleThread extends AbstractThread {
protected static final int STEP_WAITING = Integer.valueOf(1);
protected static final int STEP_SOMETHING = Integer.valueOf(2);
protected static final int STEP_NEXT_CONTINUE = Integer.valueOf(3);
private volatile boolean cycle = true;
private Object lock = new Object();
private long waitTime = 0;
public AbstractCycleThread(String threadName, long waitTime) {
super(threadName);
init(waitTime);
}
public AbstractCycleThread(long waitTime) {
super(getFinalThreadName(AbstractCycleThread.class.getSimpleName()));
init(waitTime);
}
private void init(long waitTime) {
if (waitTime < 0) {
this.waitTime = 0;
} else {
this.waitTime = waitTime;
}
info("init cycle thread, waitTime:" + waitTime);
}
@Override
public void run() {
info("start to run cycle thread:" + getName());
int nextStep = STEP_WAITING;
try {
while (cycle) {
nextStep = beforeWaitingThenDoNextStep();
if (STEP_WAITING == nextStep) {
if (waitTime > 0) {
synchronized (lock) {
lock.wait(waitTime);
}
}
if (!afterWaitupThenDoSomething()) {
continue;
}
} else if (STEP_NEXT_CONTINUE == nextStep) {
continue;
}
// 执行业务操作
doSomething();
}
} catch (Exception e) {
error("run cycle thread error:" + getName(), e);
afterError();
return;
}
info("finish to run cycle thread:" + getName());
afterfinish();
}
/**
* 执行lock.wait休眠等待前的处理操作
* @return
*
* {@link #STEP_WAITING} 进入休眠lock.wait等待
*
* {@link #STEP_NEXT_CONTINUE} 结束当前,进入下一次循环
*
* {@link #STEP_SOMETHING} 直接进入{@link #doSomething()}操作
*
*/
protected int beforeWaitingThenDoNextStep() {
// 可自行实现,默认进入等待
return STEP_WAITING;
}
/**
* 在{@link #beforeWaitingThenDoNextStep} 返回结果为{@link #STEP_WAITING}
* 后,执行lock.wait休眠等待,等待结束后执行该方法,处理操作,默认不做任何处理,并返回true
*
* @return 是否继续执行{@link #doSomething}操作
*/
protected boolean afterWaitupThenDoSomething() {
// 可自行实现,默认不做处理,直接返回下一步
return true;
}
/**
* 友好关闭线程
* @see org.slive.thread.AbstractThread#stopFriendly()
*/
public void stopFriendly() {
if (!isAlive()) {
return;
}
// 可自行实现
// 唤醒后,设置循环标识为false
synchronized (lock) {
lock.notifyAll();
}
cycle = false;
}
}
测试:
public class CycleThreadTest {
public static void main(String[] args) {
long waitTime = 500;
// 线程间数据共享
List data = new ArrayList<>();
MyCycleThread[] mcts = new MyCycleThread[5];
for (int index = 0; index < mcts.length; index++) {
mcts[index] = new MyCycleThread(waitTime, data);
mcts[index].start();
}
int d = 1;
int cycleTime = 0;
while ((cycleTime++) < 50) {
try {
// 更新数据共享的值
data.add(d++);
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 优化关闭所有线程
for (int index = 0; index < mcts.length; index++) {
mcts[index].stopFriendly();
}
}
static class MyCycleThread extends AbstractCycleThread {
private List data;
private List tempData = new ArrayList<>();
public MyCycleThread(long waitTime, List data) {
super(getFinalThreadName(MyCycleThread.class.getSimpleName()), waitTime);
this.data = data;
}
@Override
protected boolean afterWaitupThenDoSomething() {
synchronized (data) {
if (!data.isEmpty()) {
// 如果有数据了,才继续后面的doSomething操作
tempData.addAll(data);
data.clear();
return true;
} else {
return false;
}
}
}
@Override
protected void doSomething() {
Iterator ite = tempData.iterator();
while (ite.hasNext()) {
System.out.println(System.currentTimeMillis() + " " + getName() + " do something value:" + ite.next());
ite.remove();
}
}
}
}
其它:
个人比较建议继承Thread类而不是实现Runnable接口,因为相对来说,Thread可实现的方法更多,更利于控制线程。
关于线程同步,资源共享,线程池等,与此次讨论的“优化Java线程类实现”并不冲突,处在不同的使用层次上,在此不展开讨论。