首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >线程同步

线程同步
EN

Stack Overflow用户
提问于 2013-03-28 02:31:08
回答 2查看 171关注 0票数 2

我有两个部分的问题。

  1. 我有一个类,其中包含一个函数,它只能在给定时间被任何一个线程访问。使这成为一个synchronized函数或synchronized块仍然允许多个线程,因为不同的线程在类中访问它。如何确保只有一个线程访问此代码?(见下面的代码示例)
  2. 使用同步函数,对函数的调用将排队。是否有任何方法只允许对函数的最后一次调用来访问代码?因此,如果Thread1当前正在访问我的函数,那么Thread2和Thread3尝试访问它(按这个顺序),一旦Thread1完成,只有Thread3才能获得访问权。 公共空doATask() { // i创建一个新线程,这样接口就不会阻塞新线程( new (){ @Override (){ doBackgroundTask();}).start();}私有doBackgroundTask(MyObject obj) { //执行仅由一个线程//运行的长任务,并且只接受最后排队的线程}

谢谢你的帮助!

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-03-28 02:49:21

如果示例中的第二个线程只能是return,则可以使用锁的组合,并跟踪执行该方法的最后一个线程。看起来可能是这样的:

代码语言:javascript
复制
private volatile Thread lastThread;
private final ReentrantLock lock = new ReentrantLock();

private void doBackgroundTask(Object obj) throws InterruptedException {
    Thread currentThread = Thread.currentThread();
    lastThread = currentThread;
    try {
        // wait until lock available
        lock.lockInterruptibly();
        // if a thread has arrived in the meantime, exit and release the lock
        if (lastThread != currentThread) return; 
        // otherwise
        // perform long task here that is only being run by one thread
        // and also only accepts the last queued thread
    } finally {
        lock.unlock();
    }
}

具有其他日志记录的完整工作测试,该日志记录显示线程交织,并且T2退出而不做任何操作:

代码语言:javascript
复制
class Test {

    private volatile Thread lastThread;
    private final ReentrantLock lock = new ReentrantLock();

    public static void main(String[] args) throws Exception {
        final Test instance  = new Test();
        Runnable r = new Runnable() {

            @Override
            public void run() {
                try {
                    instance.doBackgroundTask(null);
                } catch (InterruptedException ignore) {}
            }
        };
        Thread t1 = new Thread(r, "T1");
        Thread t2 = new Thread(r, "T2");
        Thread t3 = new Thread(r, "T3");
        t1.start();
        Thread.sleep(100);
        t2.start();
        Thread.sleep(100);
        t3.start();
    }

    private void doBackgroundTask(Object obj) throws InterruptedException {
        Thread currentThread = Thread.currentThread();
        System.out.println("[" + currentThread.getName() + "] entering");
        lastThread = currentThread;
        try {
            // wait until lock available
            lock.lockInterruptibly();
            // if a thread has arrived in the meantime, exit and release the lock
            if (lastThread != currentThread) return;
            // otherwise
            // perform long task here that is only being run by one thread
            // and also only accepts the last queued thread
            System.out.println("[" + currentThread.getName() + "] Thinking deeply");
            Thread.sleep(1000);
            System.out.println("[" + currentThread.getName() + "] I'm done");
        } finally {
            lock.unlock();
            System.out.println("[" + currentThread.getName() + "] exiting");
        }
    }
}

输出:

代码语言:javascript
复制
[T1] entering
[T1] Thinking deeply
[T2] entering
[T3] entering
[T1] I'm done
[T1] exiting
[T2] exiting
[T3] Thinking deeply
[T3] I'm done
[T3] exiting
票数 2
EN

Stack Overflow用户

发布于 2013-03-28 03:05:10

您需要的可能是一个等待信号来执行某些工作的工作线程。doATask()只是发送一个信号来触发工作。累积信号相当于一个信号。

代码语言:javascript
复制
final Object lock = new Object();
MyObject param = null;

public void doATask(arg) 
    synchronized(lock)
        param=arg;
        lock.notify();

MyObject awaitTask()
    synchronized(lock)
        while(param==null)
            lock.wait();
        tmp=param;
        param=null;
        return tmp;

// worker thread

public void run()
    while(true)
        arg = awaitTask();
        doBackgroundTask(arg);
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15673233

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档