我有一个以下方法,我想在以下条件下执行:
already executed
或任何有用的东西返回。 以下是我的方法:
public void initialize() {
List<Metadata> metadata = getMetadata(true);
List<Process> process = getProcess();
if (!metadata.isEmpty() && !process.isEmpty()) {
Manager.setAllMetadata(metadata, process);
}
startBackgroundThread();
}
这可能吗?我正在使用Java 7。
答案 0 :(得分:10)
@ ShayHaned的解决方案使用锁定。您可以通过AtomicBoolean
来提高效率:
AtomicBoolean wasRun = new AtomicBoolean(false);
CountDownLatch initCompleteLatch = new CountDownLatch(1);
public void initialize() {
if (!wasRun.getAndSet(true)) {
List<Metadata> metadata = getMetadata(true);
List<Process> process = getProcess();
if (!metadata.isEmpty() && !process.isEmpty()) {
Manager.setAllMetadata(metadata, process);
}
startBackgroundThread();
initCompleteLatch.countDown();
} else {
log.info("Waiting to ensure initialize is done.");
initCompleteLatch.await();
log.warn("I was already run");
}
}
以上假设您不必等待startBackgroundThread
中的工作完成。如果这样做,解决方案就变成:
AtomicBoolean wasRun = new AtomicBoolean(false);
CountDownLatch initCompleteLatch = new CountDownLatch(1);
public void initialize() {
if (!wasRun.getAndSet(true)) {
List<Metadata> metadata = getMetadata(true);
List<Process> process = getProcess();
if (!metadata.isEmpty() && !process.isEmpty()) {
Manager.setAllMetadata(metadata, process);
}
// Pass the latch to startBackgroundThread so it can
// call countDown on it when it's done.
startBackgroundThread(initCompleteLatch);
} else {
log.info("Waiting to ensure initialize is done.");
initCompleteLatch.await();
log.warn("I was already run");
}
}
这样做的原因是AtomicBoolean.getAndSet(true)
将在一个原子操作中返回先前设置的值,并使新值为true
。因此,获取方法的第一个线程将返回false
(因为变量初始化为false),并且原子地将其设置为true。由于第一个线程返回false,它将采用if
语句中的第一个分支,并且您的初始化将会发生。任何其他调用都会发现wasRun.getAndSet
返回true
,因为第一个线程将其设置为true,因此他们将获取第二个分支,您将获得所需的日志消息。
CountDownLatch初始化为1,因此除了第一个调用await
之外的所有线程。它们将阻塞,直到第一个线程调用countDown
,这将把计数设置为0,释放所有等待的线程。
答案 1 :(得分:2)
您可以为方法创建静态标志,只有在调用方法后才会更改。使用静态标志背后的想法是它不属于它属于类的实例,这意味着从同一个类创建的所有线程都可以访问相同的标志值,因此一旦第一次调用后更改了标志的布尔值方法所有其他线程将被if else条件语句绕过。
static boolen flag;
public void initialize() {
if (flag)
{// return from here or some message you want to generate
}else{
List<Metadata> metadata = getMetadata(true);
List<Process> process = getProcess();
if (!metadata.isEmpty() && !process.isEmpty()) {
Manager.setAllMetadata(metadata, process);
}
flag = true;
startBackgroundThread(); }}
我希望这能解决你的问题
答案 2 :(得分:1)
•它应该只由一个线程执行。因此,如果多个线程正在调用下面的方法,那么它应该只由一个线程调用,而其他线程应该等待初始化完成?
public static final Object singleThreadLock = new Object();
public void initialize()
{
synchronized( singleThreadLock )
{
List<Metadata> metadata = getMetadata(true);
List<Process> process = getProcess();
if (!metadata.isEmpty() && !process.isEmpty())
{
Manager.setAllMetadata(metadata, process);
}
startBackgroundThread();
}
}
初始化()的这些代码行GUARANTEE每个线程只调用一次,并且因为singleThreadLock被声明为静态,所以当前生成的JVM将永远不允许任何其他线程获得对锁的访问,直到块内部同步完全执行。请远离尝试synchronized(this),因为这样的语句可能会导致严重的并发问题。