【问题标题】:Mutex with priority in JAVAJAVA中具有优先级的互斥锁
【发布时间】:2016-05-19 15:42:55
【问题描述】:

我需要优先构建我称之为“不公平信号量”的东西。 例如:当一个priority = 1的线程想要获取信号量时,它只需要等到另一个具有相同优先级的线程完成后,它就可以acquire()。但是当一个priority = 2的线程想要获取信号量时,它必须等待所有priority = 1的线程完成后才能使用信号量,然后再尝试acquire()。 我总共有 4 个不同的优先级。 这是我尝试过的方法,但没有成功。

有人有解决办法吗?

public class UnfairSemaphore
{
    private Semaphore mPrior1;
    private Semaphore mPrior2;
    private Semaphore mPrior3;
    private Semaphore mPrior4;

    public UnfairSemaphore()
    {
        mPrior1 = new Semaphore(1);
        mPrior2 = new Semaphore(1);
        mPrior3 = new Semaphore(1);
        mPrior4 = new Semaphore(1);
    }

    public void acquire(int priority) throws InterruptedException
    {
        if(priority == 1)
        {
            mPrior1.acquire();
        }
        else if(priority == 2)
        {
            while(mPrior1.hasQueuedThreads() && mPrior1.availablePermits() <=0)
            {
                //wait();
            }
            mPrior2.acquire();
            mPrior1.acquire();
        }
        else if(priority == 3)
        {
            while(mPrior1.hasQueuedThreads() && mPrior1.availablePermits() <=0 && mPrior2.hasQueuedThreads() && mPrior2.availablePermits() <=0)
            {
                //wait();
            }
            mPrior3.acquire();
            mPrior2.acquire();
            mPrior1.acquire();
        }
        else
        {
            while(mPrior1.hasQueuedThreads() && mPrior1.availablePermits() <=0 && mPrior2.hasQueuedThreads() && mPrior2.availablePermits() <=0 && mPrior3.hasQueuedThreads() && mPrior3.availablePermits() <=0)
            {
                //wait();
            }
            mPrior4.acquire();
            mPrior3.acquire();
            mPrior2.acquire();
            mPrior1.acquire();
        }
    }

    public void release(int priority)
    {
        if(priority == 1)
        {
            mPrior1.release();
        }
        else if(priority == 2)
        {           
            mPrior1.release();
            mPrior2.release();          
        }
        else if(priority == 3)
        {           
            mPrior1.release();
            mPrior2.release();
            mPrior3.release();
        }
        else
        {           
            mPrior1.release();
            mPrior2.release();
            mPrior3.release();
            mPrior4.release();
        }
        //notifyAll();
    }
}

【问题讨论】:

  • “但它没有用”它做了什么?

标签: java multithreading mutex semaphore


【解决方案1】:

基本要求是,我们有一堆等待线程,每个线程都有一个优先级。在release()上,我们选择一个优先级最高的等待线程,并将其唤醒。

这可以通过LockSupport 中的线程park()unpark() 来完成。它是一个低级并发工具,但我们不是为了精英而使用它;我们使用它是因为它最自然地模拟了我们的解决方案。

首先,我们需要一个数据结构来存储等待线程及其优先级。您可以通过多种方式做到这一点。

    void storeWaitingThread(Integer priority, Thread thread) { ... }

    // select and remove a waiting thread with highest priority; return null if none.
    Thread selectWaitingThread(){ ... }

现在,release() 只会选择一个等待线程,然后unpark

final Object lock = new Object();

volatile Thread owningThread;

public void release()
{
    synchronized (lock)
    {
        Thread nextOwner = selectWaitingThread();
        owningThread = nextOwner;
    }
    LockSupport.unpark(owningThread);
}

acquire(priority) 会将当前线程存储为等待线程;停放直到它被选中

public void acquire(int priority)
{
    Thread thisThread = Thread.currentThread();
    synchronized (lock)
    {
        if(owningThread==null)
        {
            owningThread=thisThread;
            return;
        }
        storeWaitingThread(priority, thisThread);
    }

    while(owningThread!=thisThread)
    {
        LockSupport.park();
        // interrupt ignored. // todo handle interrupt
    }
}

https://gist.github.com/zhong-j-yu/3ea91194f55d91059789查看完整代码

请注意,我们的acquire 将忽略中断。如果它应该避免中断,请在park() 唤醒后添加一些逻辑。

【讨论】:

  • 我没有测试过 :) 自己试试看是否有效。
【解决方案2】:

为什么要自己管理线程?

您应该使用 Thread 类中的 synchronised 关键字和 setPriority 方法。

查看以下链接:

https://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#setPriority%28int%29

https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html

【讨论】:

  • 可能是个好建议,但 Java 标准版中的“优先级”意义不大。如果 OP需要优先级来真正有意义(即,如果应用程序有严格的实时要求),那么它应该在实时 Java 平台上运行。
  • 线程优先级并不像您认为的那样。地狱同步一开始就不是一个公平的锁(不错的选择,公平的锁的性能很糟糕)
  • 问题是优先级不取决于Thead,而是取决于“线程需要访问资源的位置”。然后有时优先级较低,有时优先级较高。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-12-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多