thread.join
在多线程程序的编写中,为了同步线程的执行状态,我们为了方便,经常会使用thread.join()方法,须不知此方法有重大的性能缺陷,能将多线程程序变成单线程程序,执行时间瞬间翻倍,示例如下:
/**
* 用于长时间的任务计算,一般求fabic(40)就会花费1秒的时间
* 花费时间呈指数增长速度
*/
static long fabic(int n) {
if(n < 0) {
throw new numberformatexception("不能小于0");
}
if(n == 1 || n == 2) {
return 1;
}
return fabic(n - 1) + fabic(n - 2);
}
public static void main(String[] args) throws InterruptedException {
long startTime = system.currenttimemillis();
int NUM = 3;
for(int i = 0; i < NUM; i ++) {
// 创建线程
Thread th = new Thread(() -> {
fabic(35 + i);
});
th.start();
th.join();
}
// 打印花费的时间
System.out.println(System.currentTimeMillis() - startTime);
}
通过监测应用程序的执行时间,或者在线程内添加调试日志,我们发现,现在三个线程会依次执行,即线程0执行完了才执行线程1,类似于连续调用了3次th.run()方法(其实效率更低,因为还有线程创建、切换、销毁的时间)。
在上述的代码测试中,我们还发现了一个令人惊讶的现象,调用fabic的递归函数,java的执行时间竟然超过Python 100多倍,下面是成绩对比:
斐波那契数N | JAVA(ms) | Python(ms) | 结果 |
---|---|---|---|
35 | 31 | 2991 | 9227465 |
40 | 362 | 33533 | 102334155 |
当然用递归求斐波那契数的方法绝对不是一种高效的方法,但能否说明Python对递归优化得不够,还是Python对栈桢的设计策略存在问题?更高效的求斐波那契数的方法如下:
# 用公式求导更快
def fabic(n):
if(n < 1):
raise Exception('the argument can not less than 0')
# 辅助数组
result = [0, 1, 1]
if(n < 2):
return 1
while(n > 2):
result.pop(0)
result.APPend(result[0] + result[1])
n = n - 1
else:
return result[2]
所以,除了在调试环境中,可以执行Thread.join()方法,否则还不如不要启动线程,直接执行方法调用,正确的方法是应该使用countdownlatch、CyclicBarrier这样的线程工具,如下:
static class FabicTask implements Runnable {
private int num;
private final CyclicBarrier barrier;
public FabicTask(int num, CyclicBarrier barrier) {
super();
this.num = num;
this.barrier = barrier;
}
public void run() {
fabic(num);
try {
// 发信号等待结束
this.barrier.await();
} catch (InterruptedException e) {
e.printstacktrace();
} catch (brokenBarrierException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws InterruptedException {
int NUM = 3;
long startTime = System.currentTimeMillis();
CyclicBarrier barrier = new CyclicBarrier(NUM, () -> {
// 计算耗费时间
System.out.println(System.currentTimeMillis() - startTime);
});
for(int i = 0; i < NUM; i ++) {
new Thread(new FabicTask(41, barrier)).start();
}
}
结论
不要再生产环境中使用Thread.join()方法。