就以alibaba的笔试题举例吧。
题目大概的意思如下:
有一个篮子,最多容纳5个苹果。有人一直往里放苹果。有人一直去苹果。写出实现。
ali要求不能用concurrent包里面的东西,所以只能用最简单的notify和wait。
如果可以用concurrent包里面的东西,还可以用blockingqueue和signal、await。
下面实现三种方式:
Method1. notigyAll()/notify()/wait
public class Basket {
private int size = 0;
public synchronized void putApple(){
//疑问为什么要用while循环
if(size >=5){
try {
System.out.println(" 篮子中已经有5个了,到达了上限");
wait();
} catch (Exception e) {
// TODO: handle exception
}
}
this.size++;
System.out.println(">> 当前篮子内苹果数"+size);
notifyAll();
}
public synchronized void getApple(){
if(size<=0){
try {
System.out.println("篮子里面已经没有苹果了。到达了下限。");
wait();
} catch (Exception e) {
// TODO: handle exception
}
}
this.size--;
System.out.println("<< 当前篮子内苹果数"+size);
notifyAll();
}
public synchronized int getSize(){
return this.size;
}
}
public class Get implements Runnable{
private Basket basket = null;
public Get(Basket basket){
this.basket=basket;
}
public void run() {
// TODO Auto-generated method stub
while(!Thread.interrupted()){
basket.getApple();
}
}
}
public class Put implements Runnable {
private Basket basket = null;
public Put(Basket basket){
this.basket=basket;
}
public void run(
// TODO Auto-generated method stub
while(!Thread.interrupted()){
basket.putApple();
}
}
}
public class test {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Executor exe = Executors.newFixedThreadPool(2);
Basket basket = new Basket();
exe.execute(new Put(basket));
exe.execute(new Get(basket));
}
}
注意,我在测试类里面用了concurrent的executor,测试类无所谓了。
Mtthod2>BlockingQueue
public class Basket {
//篮子的载体,一个blockingQueue
private LinkedBlockingQueue list
= new LinkedBlockingQueue(5);
//放入篮子里面
public void putApple(){
System.out.println(">> 当前篮子数量 "+list.size());
if(list.size()>=5){
System.out.println(" 篮子已满。");
}
try {
list.put(new Integer(1));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//从篮子取出
public void getApple(){
System.out.println("<< 当前篮子数量 "+list.size());
if(list.size()<=0){
System.out.println(" 篮子已空。 ");
}
try {
list.take();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public class Get implements Runnable {
private Basket bakset;
public Get(Basket basket){
this.bakset=basket;
}
public void run() {
// TODO Auto-generated method stub
while(!Thread.interrupted()){
bakset.getApple();
}
}
}
public class Put implements Runnable {
private Basket basket;
public Put(Basket basket){
this.basket=basket;
}
public void run() {
// TODO Auto-generated method stub
while(!Thread.interrupted()){
basket.putApple();
}
}
}
public class test {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Executor exe = Executors.newCachedThreadPool();
Basket basket = new Basket();
exe.execute(new Get(basket));
exe.execute(new Put(basket));
}
}
使用BlockingQueue的时候,注意一下API就好了。注意 是 put 和 take 函数。
Method3.Signal、Await
public class Basket {
private int size = 0;
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
public void putApple(){
lock.lock();
System.out.println("<< "+size+" apple left" );
try {
if(this.size>=5){
condition.await();
}
this.size++;
condition.signalAll();
} catch (Exception e) {
// TODO: handle exception
}finally{
lock.unlock();
}
}
public void getApple(){
lock.lock();
System.out.println(">> "+size+" apple left" );
try {
if(this.size<=0){
condition.await();
}
this.size--;
condition.signalAll();
} catch (Exception e) {
// TODO: handle exception
}finally{
lock.unlock();
}
}
public synchronized int getSize(){
return this.size;
}
}
public class Get implements Runnable{
private Basket basket = null;
public Get(Basket basket){
this.basket=basket;
}
public void run() {
// TODO Auto-generated method stub
while(!Thread.interrupted()){
basket.getApple();
}
}
}
public class Put implements Runnable {
private Basket basket = null;
public Put(Basket basket){
this.basket=basket;
}
public void run() {
// TODO Auto-generated method stub
while(!Thread.interrupted()){
basket.putApple();
}
}
}
public class test {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Executor exe = Executors.newFixedThreadPool(2);
Basket basket = new Basket();
exe.execute(new Put(basket));
exe.execute(new Get(basket));
}
}
根据demo可以明显看出:signal、await是与lock配合用的。而wait、notify是与synchonized配合用的。因此前者拥有更好的灵活性。