我是Java的新手,所以我有一个简单的问题,我不知道从哪里开始 - 我需要编写一个接受Action的函数,在多线程程序中,只有进入函数的第一个线程执行操作,所有其他线程等待他完成,然后从函数返回而不做任何东西。
正如我所说 - 我不知道从哪里开始因为, 首先 - 在函数中没有静态var(静态就像在c / c ++中那样)所以如何让它只有第一个线程才能启动动作,其他什么都不做? 第二 - 对于要等待的线程,我应该使用
public synchronized void lala(Action doThis)
{....}
或者我应该在函数
中写出类似的东西synchronized (this)
{
...
notify();
}
谢谢!
答案 0 :(得分:3)
如果希望到达方法的所有线程都等待第一个,那么它们必须在公共对象上同步。它可以是调用方法的相同实例(this),也可以是任何其他对象(显式锁对象)。
如果你想确保第一个线程是唯一一个将执行该操作的线程,那么你必须将这个事实存储在某个地方,以便所有其他线程读取,因为它们将执行相同的指令。
按照前两点,可以锁定这个“事实”变量以达到预期的结果
static final AtomicBoolean flag = new AtomicBoolean(false); // synchronize on this, and also store the fact. It is static so that if this is in a Runnable instance will not appear to reset the fact. Don't use the Boolean wrapper, for the value of the flag might be different in certain cases.
public void lala(Action doThis)
{
synchronized (flag) // synchronize on the flag so that other threads arriving here, will be forced to wait
{
if(!flag.get()) // This condition is true only for the first thread.
{
doX();
flag.set(true); //set the flag so that other threads will not invoke doX.
}
}
...
doCommonWork();
...
}
答案 1 :(得分:3)
如果你在任何最新版本的Java中进行线程处理,你真的应该使用java.util.concurrent
包而不是直接使用Thread
。
这是你可以做到的一种方式:
private final ExecutorService executor = Executors.newCachedThreadPool();
private final Map<Runnable, Future<?>> submitted
= new HashMap<Runnable, Future<?>>();
public void executeOnlyOnce(Runnable action) {
Future<?> future = null;
// NOTE: I was tempted to use a ConcurrentHashMap here, but we don't want to
// get into a possible race with two threads both seeing that a value hasn't
// been computed yet and both starting a computation, so the synchronized
// block ensures that no other thread can be submitting the runnable to the
// executor while we are checking the map. If, on the other hand, it's not
// a problem for two threads to both create the same value (that is, this
// behavior is only intended for caching performance, not for correctness),
// then it should be safe to use a ConcurrentHashMap and use its
// putIfAbsent() method instead.
synchronized(submitted) {
future = submitted.get(action);
if(future == null) {
future = executor.submit(action);
submitted.put(action, future);
}
}
future.get(); // ignore return value because the runnable returns void
}
请注意,这假定您的Action
类(我假设您不是javax.swing.Action
,对吗?)实现Runnable
并且合理实现{{1} }和equals()
。否则,您可能需要使用其他hashCode()
实现(例如,Map
)。
此外,这假设您可能只有一次要执行的多个不同操作。如果情况并非如此,那么您可以完全删除地图并执行以下操作:
IdentityHashMap
答案 2 :(得分:1)
public synchronized void foo()
{
...
}
相当于
public void foo()
{
synchronized(this)
{
...
}
}
所以这两个选项中的任何一个都应该有用。我个人喜欢同步方法选项。
答案 3 :(得分:1)
如果只有代码的某一部分处理共享数据(例如,每个线程正在更新的公共变量),同步整个方法有时可能会过度。
性能的最佳方法是仅在共享数据周围使用synchronized关键字。如果你在完全不一定的情况下同步了整个方法,那么很多线程在他们仍可以在自己的本地范围内工作时会等待。
当一个线程进入同步时,它获取一个锁(如果你使用这个对象它锁定在对象本身上),另一个将等到锁获取线程退出。在这种情况下,您实际上不需要 notify 语句,因为线程将在退出synchronize语句时释放锁定。