java.util.concurrent.locks 包中,规定了三个接口,来代替synchronized和Object的监视器方法,wait,notify。
即帮助我们更加灵活的控制线程的状态和同步。至于如何使用Lock请参考ReentrantLock和synchronized的区别
- Condition 代替Object的监视器方法,wait,notify。
- Lock 代替synchronized关键字
- ReadWriteLock 实现读写锁,写写互斥,读写互斥,读读不互斥。
本文使用Condition实现一个固定同步容器。
在容器已满时,生产者的线程等待,生产者生产时,即唤醒所有等待的消费者(如果有的话)。
在容器已空时,消费者的容器等待,消费者消费时,即唤醒所有等待的生产者(如果有的话)。
import java.util.Arrays;
/**
* 使用synchronized和Object.wait();Object.notifyAll();
* 完成的固定长度同步容器
* @author TomcatLikeYou
* @param <E>
*/
public class SynchronizedContainer<E>
{
private int size = 10;
private E[] array = null;
private int index = 0;
@SuppressWarnings("all")
public SynchronizedContainer()
{
array = (E[]) new Object[size];
}
@SuppressWarnings("all")
public SynchronizedContainer(int size)
{
this.size = size;
array = (E[]) new Object[size];
}
public synchronized void add(E element)
{
while (index >= size)
{
try
{
System.out.println("线程:" + Thread.currentThread().getName() + " 等待消费");
this.wait();
System.out.println("线程:" + Thread.currentThread().getName() + " 被唤醒");
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
array[index] = element;
index++;
System.out.println("线程:" + Thread.currentThread().getName() + " 将数组增加至" + this.toString());
this.notifyAll();
}
public synchronized E get()
{
while (index <= 0)
{
try
{
System.out.println("线程:" + Thread.currentThread().getName() + " 等待生产");
this.wait();
System.out.println("线程:" + Thread.currentThread().getName() + " 被唤醒");
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
index--;
E element = array[index];
//下面语句这是没必要的操作,但是为了看的清楚被消费了,加上这句
array[index] = null;
this.notifyAll();
System.out.println("线程:" + Thread.currentThread().getName() + " 将数组减少至" + this.toString());
return element;
}
@Override
public String toString()
{
return Arrays.toString(array);
}
public static void main(String[] args)
{
SynchronizedContainer array = new SynchronizedContainer(20);
for (int i = 0 ; i <2 ; i++)
{
new Thread(()->{
for (int j = 0 ; j < 500 ; j++)
{
array.get();
}
},"消费者线程" + String.valueOf(i)).start();
}
for (int i = 0 ; i <10 ; i++)
{
new Thread(()->{
for (int j = 0 ; j < 100 ; j++)
{
array.add(String.valueOf(j));
}
},"生产者线程" + String.valueOf(i)).start();
}
}
}
import java.util.Arrays;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 使用Lock和Condition
* 完成的固定长度同步容器
* @author TomcatLikeYou
*/
public class ConditionLockContainer<E>
{
//容器的大小
private int size = 10;
//实际存储容器的数组
private E[] array = null;
//index表示下一个能被添加的元素在数组中的下标
private int index = 0;
//实现同步的锁
Lock lock = new ReentrantLock();
//get条件
Condition getCondition = lock.newCondition();
//put条件
Condition addCondition = lock.newCondition();
//不用加synchronized,内部使用了lock加锁
public E get()
{
//获取锁
lock.lock();
E element;
//由于如果lock时发生异常,不会自动释放锁,故在finally中释放锁(虽然此例中不需要)
try
{
//只要index等于0,就等待
while (index <= 0)
{
try
{
System.out.println("线程:" + Thread.currentThread().getName() + " 等待生产");
getCondition.await();
System.out.println("线程:" + Thread.currentThread().getName() + " 被唤醒");
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
index--;
element = array[index];
//下面语句这是没必要的操作,但是为了看的清楚被消费了,加上这句
array[index] = null;
//唤醒所有等待的生产者线程
System.out.println("线程:" + Thread.currentThread().getName() + " 将数组减少至" + this.toString());
addCondition.signalAll();
}
finally
{
//释放锁
lock.unlock();
}
return element;
}
public void add(E element)
{
lock.lock();
try
{
while (index >= size)
{
try
{
System.out.println("线程:" + Thread.currentThread().getName() + " 等待消费");
addCondition.await();
System.out.println("线程:" + Thread.currentThread().getName() + " 被唤醒");
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
array[index] = element;
index++;
System.out.println("线程:" + Thread.currentThread().getName() + " 将数组增加至" + this.toString());
//唤醒所有生产者线程
getCondition.signalAll();
}
finally
{
lock.unlock();
}
}
@SuppressWarnings("all")
public ConditionLockContainer()
{
array = (E[]) new Object[size];
}
@SuppressWarnings("all")
public ConditionLockContainer(int size)
{
this.size = size;
array = (E[]) new Object[size];
}
@Override
public String toString()
{
return Arrays.toString(array);
}
public static void main(String[] args)
{
ConditionLockContainer array = new ConditionLockContainer(20);
for (int i = 0 ; i <2 ; i++)
{
new Thread(()->{
for (int j = 0 ; j < 500 ; j++)
{
array.get();
}
},"消费者线程" + String.valueOf(i)).start();
}
for (int i = 0 ; i <10 ; i++)
{
new Thread(()->{
for (int j = 0 ; j < 100 ; j++)
{
array.add(String.valueOf(j));
}
},"生产者线程" + String.valueOf(i)).start();
}
}
}
分析代码可知,使用Condition效率会更高,更灵活,唤醒的不是所有等待线程,而是指定线程。而且Condition的await可以指定多个不同方法,见API文档