Mam następujący problem, możliwe, że popełniłem błąd i go po prostu nie widzę, ale to co obserwuje, jest dla mnie dziwne. Pomimo, że proces śpi na jakimś obiekcie monitorze, to inny wątek wysyłający do niego powiadomienie za pomocą notify na tym samym obiekcie nie zawsze budzi go.
To jest bardzo losowe, by to zaobserwować (deadlock) należy bez żadnych opóźnień itd. - kręcenie się w kółko dawać operacje aquire i release. Nie zawsze się to zwiesza, ale czasami tak (co dla mnie jest niedopuszczalne).
Rozwiązaniem jakie teraz stosuje (by przebadać te zjawisko - należy to zakomentować tymczasowo w kodzie) Thread.interrupt na tym wątku, to zawsze działa i nie deadlockuje.
Czy tak może być, że notify nie dotrze do jedynego obiektu czekającym na monitorze? Czy to zwykły programistyczny bug (prosiłbym o wskazanie go, jak ktoś go znajdzie)
kod:
package tpsa.concurrency;
import java.util.ArrayList;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class PrioritySemaphore {
private Lock lock;
private ArrayList<SemaphoreObject> threads;
private int counter;
public PrioritySemaphore(int counter) {
lock = new ReentrantLock(true);
threads = new ArrayList<>();
this.counter = counter;
}
public void aquire() {
lock.lock();
counter--;
if (counter < 0) {
SemaphoreObject l = new SemaphoreObject();
l.t = Thread.currentThread();
int idx = 0;
for (idx = 0; idx < threads.size(); idx++) {
if (threads.get(idx).t.getPriority() < l.t.getPriority())
break;
}
threads.add(idx, l);
lock.unlock();
synchronized (l) {
try {
l.wait();
} catch (InterruptedException e) {
}
Thread.currentThread().isInterrupted();
}
} else
lock.unlock();
}
public void release() {
lock.lock();
counter++;
SemaphoreObject tFirst = (threads.size() > 0) ? threads.get(0) : null;
if (tFirst != null) {
synchronized (tFirst) {
tFirst.t.interrupt();
}
threads.remove(tFirst);
}
lock.unlock();
}
}
package tpsa.concurrency;
public class SemaphoreObject {
public Thread t;
public int priority;
public SemaphoreObject()
{
t = null;
priority = 1;
}
@Override
public String toString() {
return t.getName() + "(" + priority + ")";
}
}