在Java中纠正BoundedBuffer实现?

时间:2016-03-18 05:13:13

标签: java multithreading

看到几个关于有界缓冲区的在线示例。对他们的实施不满意。我对Java比较新。对改进版本有什么好的建议或意见吗?谢谢。 例如:

import com.google.common.collect.Lists;

import java.util.List;

public class BoundedBufferNotGood {
    private final List<Integer> data;
    private final int capacity;
    private int size;
    private int head;
    private int tail;

    BoundedBufferNotGood(int capacity) {
        this.data = Lists.newArrayListWithCapacity(capacity);
        this.capacity = capacity;
        size = 0;
        head = 0;
        tail = 0;
    }

    public synchronized void put(Integer x) throws InterruptedException {
        while (size == capacity) wait();
        data.add(head, x);
        head++;
        head %= capacity;
        size++;
        notifyAll();
    }

    public synchronized Integer get() throws InterruptedException {
        while (size == 0) wait();
        Integer x = data.get(tail);
        tail++;
        tail %= capacity;
        size--;
        notifyAll();
        return x;
    }
}

此代码可以正常工作,但在不必要的睡眠和唤醒方面非常糟糕。 put()中的wait()函数和get()等待这个。但他们应该等待不同的。在get()方法中,wait()应该等待大小&gt; 0,put()应该等待大小&lt;容量。

改进版本:

import com.google.common.collect.Lists;

import java.util.List;

public class BoundedBuffer {
    private final List<Integer> data;
    private final int capacity;
    private int size;
    private int head;
    private int tail;
    private final Object dataCV = new Object();
    private final Object spaceCV = new Object();

    BoundedBuffer(int capacity) {
        this.data = Lists.newArrayListWithCapacity(capacity);
        this.capacity = capacity;
        size = 0;
        head = 0;
        tail = 0;
    }

    public synchronized void put(Integer x) throws InterruptedException {
        while (size == capacity) {
            synchronized (spaceCV) { // do we need to move synchronized() outside of while loop?
                wait();
            }
        }
        data.add(head, x);
        head++;
        head %= capacity;
        size++;
        dataCV.notifyAll();
    }

    public synchronized Integer get() throws InterruptedException {
        while (size == 0) {
            synchronized (dataCV) {
                wait();
            }
        }
        Integer x = data.get(tail);
        tail++;
        tail %= capacity;
        size--;
        spaceCV.notifyAll();
        return x;
    }
}

2 个答案:

答案 0 :(得分:1)

  put()中的

wait()函数和get()在相同条件下等待

使用java.util.concurrent.locks.ReentrantLock代替synchronized

ReentrantLock的优点是你可以从同一个锁对象中获得两个(或更多)条件变量,因此你可以让一个条件让生产者等待,并为消费者提供不同的条件,但每个人锁定相同的锁。

使用

Lock myLock = new ReentrantLock();

创建锁定对象,然后使用

Condition producerCondition = myLock.newCondition();
Condition consumerCondition = myLock.newCondition();

创建两个条件变量。

然后你可以使用:

myLock.lock();   //instead of entering a synchronized block,
myLock.unlock(); //instead of leaving the synchronized block,

consumerCondition.await();   // instead of this.wait();
consumerCondition.signal();  // instead of this.notifyAll();

提示:使用try { ... } finally { ... }确保锁定已解锁。

答案 1 :(得分:0)

感谢大家。使用Condition的新版本。

import com.google.common.collect.Lists;
import net.jcip.annotations.GuardedBy;

import java.util.List;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class BoundedBuffer {
    @GuardedBy("lock”) private final List<Integer> data;
    @GuardedBy("lock”) private final int capacity;
    @GuardedBy("lock") private int size;
    @GuardedBy("lock”) private int head;
    @GuardedBy("lock”) private int tail;

    Lock lock = new ReentrantLock();
    private final Condition spaceCondition = lock.newCondition();
    private final Condition dataCondition = lock.newCondition();

    BoundedBuffer(int capacity) {
        this.data = Lists.newArrayListWithCapacity(capacity);
        this.capacity = capacity;
        size = 0;
        head = 0;
        tail = 0;
    }

    public void put(int x) throws InterruptedException {
        lock.lock();
        try {
            while (size == capacity) {
                spaceCondition.await();
            }
            data.add(head, x);
            head++;
            head %= capacity;
            size++;
            dataCondition.signalAll();
        } finally {
            lock.unlock();
        }
    }

    public int get() throws InterruptedException {
        lock.lock();
        try {
            while (size == 0) {
                dataCondition.await();
            }
            int x = data.get(tail);
            tail++;
            tail %= capacity;
            size--;
            spaceCondition.signalAll();
            return x;
        } finally {
            lock.unlock();
        }
    }
}