2016-02-09 3 views
2

Мне нужно создать то, что я называю «Несправедливый Семафор» с приоритетом. Например: когда поток с priority = 1 хочет приобрести семафор, ему просто нужно подождать, пока другой поток с тем же приоритетом не будет завершен, тогда он может acquire(). Но когда поток с priority = 2 хочет получить семафор, ему нужно дождаться, пока все потоки с priority = 1 закончатся, прежде чем использовать семафор, а затем попробуйте acquire(). У меня есть 4 разных приоритета. Вот что я пробовал, но это не сработало.Мьютекс с приоритетом в JAVA

У кого-нибудь есть решение?

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(); 
    } 
} 
+4

«но это не сработало», что он сделал вместо этого? –

ответ

-1

Зачем руководить резьбой самостоятельно?

Из класса 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

+0

Вероятно, хороший совет, но «приоритеты» в стандартном выпуске Java имеют очень мало смысла. Если OP _needs_ приоритеты действительно означают что-то (то есть, если приложение имеет жесткие требования в режиме реального времени), то он должен запускаться на платформе Java реального времени. –

+0

Приоритеты нитей не делают то, что вы, кажется, думаете, что они делают. Хел синхронизирован - это не честный замок для начала (хороший выбор, честные блокировки - ужасная производительность) – Voo

+0

Проблема в том, что приоритет не зависит от Thead, а от того, «где поток должен получить доступ к ressource». Тогда иногда это будет с меньшим приоритетом, иногда с высшим. – Vanpourix

0

Основное требование заключается в том, что у нас есть куча ожидающих потоков, каждый из которых имеет приоритет. В поле release() мы выбираем ожидающий поток с наивысшим приоритетом и пробуждаем его.

Это может быть сделано нитью park() и unpark() в LockSupport. Это низкоуровневый инструмент параллелизма, но мы не используем его для элиты; мы используем его, потому что он наиболее естественно моделирует наше решение.

Для начала нам нужна структура данных, в которой хранятся ожидающие потоки вместе с их приоритетами. Вы можете сделать это разными способами.

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().

+0

Я его не тестировал :) Попробуйте сами и посмотрите, работает ли это. – ZhongYu

Смежные вопросы