6.饥饿和公平

饥饿

如果一个线程因为CPU时间全部被其他线程抢走而得不到CPU运行时间,这种状态被称之为“饥饿”。

导致饥饿的原因

  • 高优先级线程吞噬所有的低优先级线程的CPU时间
  • 线程被永久堵塞在一个等待进入同步块的状态
  • 线程在等待一个本身也处于永久等待完成的对象(比如调用这个对象的wait方法)

实现Java的公平性

  • 使用Locks取代Synchronized块
public class Synchronizer{
  Lock lock = new Lock();

  public void doSynchronized() throws InterruptedException{
    this.lock.lock();
      //critical section, do a lot of work which takes a long time
    this.lock.unlock();
  }
}

public class Lock{
  private boolean isLocked = false;
  private Thread  lockingThread = null;

  public synchronized void lock() throws InterruptedException{
    while(isLocked){
      wait();
    }
    isLocked = true;
    lockingThread = Thread.currentThread();
  }

  public synchronized void unlock(){
    if(this.lockingThread != Thread.currentThread()){
      throw new IllegalMonitorStateException(
        "Calling thread has not locked this lock");
    }
    isLocked = false;
    lockingThread = null;
    notify();
  }
}

这个版本的lock方法和synchronized就公平性而言,没有任何区别

  • 使用公平锁
public class FairLock {
    private boolean isLocked = false;
    private Thread lockingThread  = null;
    private List waitingThreads =
            new ArrayList();

    public void lock() throws InterruptedException{
        QueueObject queueObject = new QueueObject();
        boolean isLockedForThisThread = true;
        synchronized(this){
            waitingThreads.add(queueObject);
        }

        while(isLockedForThisThread){
          synchronized(this){
            isLockedForThisThread =
                isLocked || waitingThreads.get(0) != queueObject;
            if(!isLockedForThisThread){
              isLocked = true;
               waitingThreads.remove(queueObject);
               lockingThread = Thread.currentThread();
               return;
             }
          }
          try{
            queueObject.doWait();
          }catch(InterruptedException e){
            synchronized(this) { waitingThreads.remove(queueObject); }
            throw e;
          }
        }
    }

    public synchronized void unlock(){
        if(this.lockingThread != Thread.currentThread()){
          throw new IllegalMonitorStateException(
            "Calling thread has not locked this lock");
        }
        isLocked = false;
        lockingThread = null;
        if(waitingThreads.size() > 0){
          waitingThreads.get(0).doNotify();
        }
    }
}

public class QueueObject {

  private boolean isNotified = false;

  public synchronized void doWait() throws InterruptedException {
    while(!isNotified){
        this.wait();
    }
    this.isNotified = false;
  }

  public synchronized void doNotify() {
    this.isNotified = true;
    this.notify();
  }

  public boolean equals(Object o) {
    return this == o;
  }
}

FairLock新创建了一个QueueObject的实例,并对每个调用lock()的线程进行入队列。调用unlock()的线程将从队列头部获取QueueObject,并对其调用doNotify(),以唤醒在该对象上等待的线程。通过这种方式,在同一时间仅有一个等待线程获得唤醒,而不是所有的等待线程。

你可能感兴趣的:(6.饥饿和公平)