我有一个正在被多个线程访问的类..我希望该类做一些事情 在它可以响应调用(getSomething)之前。
我正在考虑在类构造函数中启动 SampleThread,但我不喜欢在内部启动线程的想法 构造函数。
我正在考虑做这样的事情,但我不确定这是否正确。 第一个在我的类上调用 getSomething 的线程将启动一个线程..
但我仍然不确定这是否正确。我担心多个 SampleThread 会运行,而我希望它只运行一次。
public class A{
private final AtomicBoolean isReady = new AtomicBoolean(false);
public A{
}
public void getSomething(){
if(!isReady.get()){
new SampleThread().start();
}
//continue with the rest of the method
}
}
public class SampleThread{
public void run(){
//Do some long running task once done
isReady.set(true);
}
}
我没有办法添加一个名为 start() 的方法来调用我的 SampleThread,因为这是由框架调用的。
有什么提示吗?
更新2
我尝试了一个示例类来模拟这一点,并使用了一个闩锁来等待我的 InitializerThread 完成。
package com.race;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
public class TestRaceCondition {
public static class SampleClass implements Runnable {
private final CountDownLatch latch = new CountDownLatch(1);
private final AtomicBoolean isReady = new AtomicBoolean(false);
public void doSomething() {
synchronized (this) {
if (!isReady.get()) {
System.out.println(Thread.currentThread().getName() + " is initializing the system....");
new InitializerThread(latch).start();
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
isReady.set(true);
}
}
System.out.println("Doing something...." + Thread.currentThread().getName());
System.out.println("Still doing something...." + Thread.currentThread().getName());
}
@Override
public void run() {
// System.out.println(Thread.currentThread().getName() + " :: is running!");
doSomething();
}
}
public static class InitializerThread extends Thread {
private CountDownLatch latch;
public InitializerThread(CountDownLatch latch) {
this.latch = latch;
}
@Override
public void run() {
// Simulate some long running task
System.out.println(Thread.currentThread().getName() + " is calling a long running task....");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
latch.countDown();
}
}
public static void main(String[] args) {
SampleClass myClass = new SampleClass();
Thread t1 = new Thread(myClass);
Thread t2 = new Thread(myClass);
Thread t3 = new Thread(myClass);
Thread t4 = new Thread(myClass);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
但我不确定结果有什么问题..
Initializing system....
Calling a long running task....
Initializing system....
Doing something....Thread-0
Still doing something....Thread-0
Doing something....Thread-3
Still doing something....Thread-3
Calling a long running task....
Initializing system....
Doing something....Thread-2
Still doing something....Thread-2
Calling a long running task....
Initializing system....
Doing something....Thread-1
Still doing something....Thread-1
Calling a long running task....
它似乎仍在多次调用我的初始化器线程...... 我添加了锁存器,但我的输出有问题。
我一直在期待这样的事情......
Initializing system....
Calling a long running task....
Doing something....Thread-0
Still doing something....Thread-0
Doing something....Thread-3
Still doing something....Thread-3
Doing something....Thread-2
Still doing something....Thread-2
Doing something....Thread-1
Still doing something....Thread-1
更新3 我根据建议编辑了代码以包含同步...
Thread-0 is initializing the system....
Thread-4 is calling a long running task....
Doing something....Thread-0
Still doing something....Thread-0
Doing something....Thread-2
Still doing something....Thread-2
Doing something....Thread-3
Still doing something....Thread-3
Doing something....Thread-1
Still doing something....Thread-1
我只是没有得到输出..为什么 Thread-0 正在执行初始化,而 Thread-4 正在运行该任务。我期望第一个线程执行长时间运行任务的初始化和调用。
最佳答案
这种方式存在竞争条件:
public void getSomething(){
if(!isReady.get()){
new SampleThread().start();
}
//continue with the rest of the method
}
这是原子的:if(!isReady.get())
,但与之关联的条件语句的主体不是:
{
new SampleThread().start();
}
所以你可以启动这个线程两次。
同步逻辑可以防止竞争条件。它还会增加对象上潜在锁定的数量,但由于 if(!isReady.get())
应该快速执行,因此应该可以接受。
请注意,如果 boolean 值仅在同步语句中使用,您可能不需要使用 AtomicBoolean
。
所以这里有两种方法,根据您的要求。
1) 允许第一次调用 getSomething()
来启动 SampleThread
,并且其他线程在执行 getSomething() 之前等待此初始化结束
:
public void getSomething(){
synchronized(this){
// init the logic
if(!isReady){
SampleThread t = new SampleThread();
t.start();
t.join(); // wait for the SampleThread thread termination
isReady.set(true);
}
// execute the next only as the init thread was terminated
if(isReady){
//continue with the rest of the method
}
}
}
2) 允许第一次调用 getSomething()
来启动 SampleThread
,并且其他线程在执行 之前不会等待此初始化结束getSomething()
:
public void getSomething(){
synchronized(this){
// init the logic once
if(!isReady.get()){
SampleThread t = new SampleThread();
t.start();
}
}
//continue with the rest of the method
}
并在 SampleThread
的 run()
末尾将 isReady
设置为 true
:
public void run(){
//Do some long running task once done
isReady.set(true);
}
关于java - 在类构造函数中调用线程的替代方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51340270/