java - 为什么这个并发的 Java 代码经常失败?
问题描述
//Initially, I wanted to compare synchronized with Lock
public class SynchronizedVSLock {
static final Lock lock = new ReentrantLock();
static final int loopTime = 10;
static final int numOfThread = 6;
static final Random random = new Random();
static final Semaphore runningThreadsNum = new Semaphore(numOfThread);
public static void main(String[] args) throws InterruptedException {
long startTime = System.currentTimeMillis();
for (int i = 0; i < numOfThread - 1; i++) {
new Thread(new Test1()).start();
}
new Thread(new Test1()).join();
runningThreadsNum.acquire(numOfThread);
long endTime = System.currentTimeMillis();
System.out.println(endTime - startTime);
}
static class Test1 implements Runnable {
@Override
public void run() {
try {
runningThreadsNum.acquire();
} catch (InterruptedException e) {
throw new RuntimeException();
}
for (int i = 0; i < SynchronizedVSLock.loopTime; i++) {
SynchronizedVSLock.lock.lock();
System.out.println(SynchronizedVSLock.random.nextDouble());
SynchronizedVSLock.lock.unlock();
}
runningThreadsNum.release();
}
}
static class Test2 implements Runnable {
@Override
public void run() {
try {
runningThreadsNum.acquire();
} catch (InterruptedException e) {
throw new RuntimeException();
}
for (int i = 0; i < SynchronizedVSLock.loopTime; i++) {
synchronized (SynchronizedVSLock.lock) {
System.out.println(SynchronizedVSLock.random.nextDouble());
}
}
runningThreadsNum.release();
}
}
}
大致思路是创建多个线程并发执行输出随机数的任务,分别使用lock和synchronized两种同步机制。最后将程序运行时间作为指标输出。使用信号量确保主线程在所有子线程都完成之前不会获得最终经过的时间但是我发现通常主线程在其他子线程运行之前获得所有权限,然后打印一个非常小的运行时间,只是一两毫秒,我不知道出了什么问题。
解决方案
您正在加入一个您没有开始的线程,而不是等待您在循环中启动的任何线程:
for (int i = 0; i < numOfThread - 1; i++) {
new Thread(new Test1()).start();
}
new Thread(new Test1()).join();
调用join()
未启动的线程会立即返回。这意味着您的初始线程可以在第一个Test1
线程开始执行之前获得信号量的所有 6 个许可,这意味着它将简单地打印时间并退出。
您应该考虑CountDownLatch
在此处使用 a 而不是信号量,因为这是它的教科书用例。
推荐阅读
- sql - 使用 SQL 文件作为 React Native 数据的数据存储库
- c - 如何将标准输入返回到控制台?
- sass - 是否可以使用 SASS 创建包含选择器的函数(或其他东西)?
- python - 如何通过 MCP3008 将 E-201C pH 传感器与树莓派接口
- python - 移动平均线交叉的错误结果
- typescript - openpgp.decrypt 在开玩笑时返回空字符串
- python - 从 django admin 创建对象时如何将当前登录的用户附加到对象
- security - 如何从哈希中识别恶意软件扩展?
- macos - MacOs-pipeline 因特定映像版本而失败
- vue.js - 单击父组件中的另一个按钮时,如何在子组件上的按钮中添加动态类名?