Как реализовать двоичный Семафорный класс в Java?
Я вижу, как "стандартный" Семафорный класс может быть реализован в Java. Однако я не вижу, как реализовать двоичный Семафорный класс в Java. Как работает такая реализация? Когда я должен вызвать методы wake и notify, чтобы разбудить и остановить потоки, которые находятся на семафорах? Я понимаю, что такое двоичные семафоры, но понятия не имею, как их кодировать.
Правка Примечание: поймите, что я сказал "двоичный" Семафорный класс. Стандартный Семафорный класс я уже сделал, и я знаю его правильно, поэтому стандартный Семафорный класс меня не интересует.
7 ответов:
Я думаю, что вы говорите о мьютексах (или блокировках взаимного исключения). Если это так, вы можете использовать встроенные замки. Этот вид блокировок в Java действует как мьютексы, что означает, что не более чем один поток может владеть блокировкой:
synchronized (lock) { // Access or modify shared state guarded by lock }
Где lock-это макет объекта, используемый только для блокировки.
Редактировать:
Вот реализация для вас-нереентерабельный класс блокировки взаимного исключения, который использует нулевое значение для представления разблокированного состояния и единицу для представления заблокированного состояния. государство.
Если вам нужно знать, куда звонитьclass Mutex implements Lock, java.io.Serializable { // Our internal helper class private static class Sync extends AbstractQueuedSynchronizer { // Report whether in locked state protected boolean isHeldExclusively() { return getState() == 1; } // Acquire the lock if state is zero public boolean tryAcquire(int acquires) { assert acquires == 1; // Otherwise unused if (compareAndSetState(0, 1)) { setExclusiveOwnerThread(Thread.currentThread()); return true; } return false; } // Release the lock by setting state to zero protected boolean tryRelease(int releases) { assert releases == 1; // Otherwise unused if (getState() == 0) throw new IllegalMonitorStateException(); setExclusiveOwnerThread(null); setState(0); return true; } // Provide a Condition Condition newCondition() { return new ConditionObject(); } // Deserialize properly private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { s.defaultReadObject(); setState(0); // reset to unlocked state } } // The sync object does all the hard work. We just forward to it. private final Sync sync = new Sync(); public void lock() { sync.acquire(1); } public boolean tryLock() { return sync.tryAcquire(1); } public void unlock() { sync.release(1); } public Condition newCondition() { return sync.newCondition(); } public boolean isLocked() { return sync.isHeldExclusively(); } public boolean hasQueuedThreads() { return sync.hasQueuedThreads(); } public void lockInterruptibly() throws InterruptedException { sync.acquireInterruptibly(1); } public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { return sync.tryAcquireNanos(1, unit.toNanos(timeout)); } }
wait()
иnotify()
, Посмотрите наsun.misc.Unsafe#park()
. Он используется в java.утиль.параллельный.блокирует пакет (AbstractQueuedSynchronizerНадеюсь, это поможет.
Вот простая реализация, которую я сделал для двоичного семафора:
public class BinarySemaphore { private final Semaphore countingSemaphore; public BinarySemaphore(boolean available) { if (available) { countingSemaphore = new Semaphore(1, true); } else { countingSemaphore = new Semaphore(0, true); } } public void acquire() throws InterruptedException { countingSemaphore.acquire(); } public synchronized void release() { if (countingSemaphore.availablePermits() != 1) { countingSemaphore.release(); } } }
Эта реализация имеет одно свойство двоичных семафоров, которое невозможно получить при подсчете семафоров, имеющих только одно разрешение-несколько вызовов для освобождения все равно оставят доступным только один ресурс. Это свойство упоминается здесь.
Здесь прямо с сайта Java
Библиотека утилит параллелизма, возглавляемая Дугом Леа в JSR-166, является специальный выпуск популярного пакета параллелизма в J2SE 5.0 платформа. Он обеспечивает мощные, высокоуровневые конструкции потока, в том числе исполнители, которые являются фреймворком потоковых задач, потокобезопасны очереди, таймеры, блокировки (в том числе атомарные) и другие примитивы синхронизации.
Одним из таких замков является хорошо известный семафор. Один семафор можно использовать в таким же образом, как ожидание используется сейчас, чтобы ограничить доступ к блоку код. Семафоры более гибки и могут также позволить несколько параллельные потоки доступа, а также позволяют протестировать блокировку перед приобретая его. В следующем примере используется только один семафор, также известен как двоичный семафор. Смотрите на яву.утиль.параллельный пакет для подробная информация.final private Semaphore s= new Semaphore(1, true); s.acquireUninterruptibly(); //for non-blocking version use s.acquire() try { balance=balance+10; //protected value } finally { s.release(); //return semaphore token }
Я думаю, что вся причина использования абстракций более высокого уровня, таких как семафор класс-это то, что вы не должны называть низким уровнем
wait
/notify
.
Да, можешь. Семафор с одним разрешением-это двоичный семафор. Они контролируют доступ к одному ресурсу. Их можно рассматривать как своего рода мьютекс/замок.
Semaphore binarySemaphore = new Semaphore(1);
Вы могли бы взглянуть на исходный код для реализации Java класса Semaphore (или, возможно, использовать его напрямую?)
У меня есть собственная реализация двоичного семафора в Java.
import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; /** * A binary semaphore extending from the Java implementation {@link Semaphore}. * <p> * This semaphore acts similar to a mutex where only one permit is acquirable. Attempts to acquire or release more than one permit * are forbidden. * <p> * Has in {@link Semaphore}, there is no requirement that a thread that releases a permit must have acquired that permit. However, * no matter how many times a permit is released, only one permit can be acquired at a time. It is advised that the program flow * is such that the thread making the acquiring is the same thread making the release, otherwise you may end up having threads * constantly releasing this semaphore, thus rendering it ineffective. * * @author Pedro Domingues */ public final class BinarySemaphore extends Semaphore { private static final long serialVersionUID = -927596707339500451L; private final Object lock = new Object(); /** * Creates a {@code Semaphore} with the given number of permits between 0 and 1, and the given fairness setting. * * @param startReleased * <code>true</code> if this semaphore starts with 1 permit or <code>false</code> to start with 0 permits. * @param fairMode * {@code true} if this semaphore will guarantee first-in first-out granting of permits under contention, else * {@code false} */ public BinarySemaphore(boolean startReleased, boolean fairMode) { super((startReleased ? 1 : 0), fairMode); } @Override public void acquire(int permits) throws InterruptedException { if (permits > 1) throw new UnsupportedOperationException("Cannot acquire more than one permit!"); else super.acquire(permits); } @Override public void acquireUninterruptibly(int permits) { if (permits > 1) throw new UnsupportedOperationException("Cannot acquire more than one permit!"); else super.acquireUninterruptibly(permits); } @Override public void release() { synchronized (lock) { if (this.availablePermits() == 0) super.release(); } } @Override public void release(int permits) { if (permits > 1) throw new UnsupportedOperationException("Cannot release more than one permit!"); else this.release(); } @Override public boolean tryAcquire(int permits) { if (permits > 1) throw new UnsupportedOperationException("Cannot acquire more than one permit!"); else return super.tryAcquire(permits); } @Override public boolean tryAcquire(int permits, long timeout, TimeUnit unit) throws InterruptedException { if (permits > 1) throw new UnsupportedOperationException("Cannot release more than one permit!"); else return super.tryAcquire(permits, timeout, unit); } }
Скажите мне, если вы найдете какую-либо ошибку в коде, пожалуйста, но до сих пор он всегда работал нормально! :)
Я бы предпочел использовать класс Lock
Помимо сопоставления имен, семафор Java не является способом реализации BinarySemaphore, и использование Object wait/notify или synchronize является довольно сырым.
Вместо этого класс Lock предоставляет почти ту же семантику блокировки, что и семафор с его блокировкой / разблокировкой (по сравнению с получением / освобождением семафором), но он специально нацелен на решение критической функциональности раздела, где ожидается, что только один поток войдет в однажды.
Стоит отметить блокировку предоставляем попробовать с семантикой ожидания благодаря tryLock Метод.