有几种实现方法,一种是通过临界缓冲区的wait和notify来协调多个线程的并发,一种可以借用jdk 1.5+自带的BlockingQueue来实现,还有一种可以通过jdk1.5+的信号量机制来控制并发。
jdk1.5- 采用Object的wait 和notify方法来实现:
package com.xx.concurrent.commonUse; import java.util.LinkedList; import java.util.Queue; import java.util.concurrent.CountDownLatch; import com.fangming.pub.StringUtils; class Productor extends Thread { Queue<String> buffer; int quality; public Productor(Queue<String> buffer, int quality) { this.buffer = buffer; this.quality = quality; } @Override public void run() { try { product(); } catch (InterruptedException e) { e.printStackTrace(); } ProductorAndCustomer.latch.countDown(); } private void product() throws InterruptedException { synchronized (buffer) { while (quality > 0) { if (buffer.size() == ProductorAndCustomer.BUFFERSIZE) { buffer.wait(); } else { String str = StringUtils.getRandomString(10); buffer.offer(str); quality--; System.out.println("####producer product " + str); buffer.notify(); } } } } } class Customer extends Thread { Queue<String> buffer; int quality; public Customer(Queue<String> buffer, int quality) { this.buffer = buffer; this.quality = quality; } @Override public void run() { try { cusume(); } catch (InterruptedException e) { e.printStackTrace(); } ProductorAndCustomer.latch.countDown(); } private void cusume() throws InterruptedException { synchronized (buffer) { while (quality > 0) { if (buffer.size() == 0) { buffer.wait(); } else { String str = buffer.poll(); System.out.println("$$$$customer cocume " + str); quality--; buffer.notify(); } } } } } public class ProductorAndCustomer { static final int BUFFERSIZE = 10; static CountDownLatch latch = new CountDownLatch(15); public static void main(String[] args) throws InterruptedException { long startTime = System.nanoTime(); Queue<String> buffer = new LinkedList<String>(); for (int i = 0; i < 10; i++) { Thread t1 = new Productor(buffer, 100); t1.start(); } for (int i = 0; i < 5; i++) { Thread t2 = new Customer(buffer, 200); t2.start(); } latch.await(); long endTime = System.nanoTime(); System.out.println(endTime - startTime); } }
jdk1.5+ 采用BlockingQueue来实现
package com.xx.concurrent.commonUse; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.CountDownLatch; public class MutiProductorAndCustomer { ArrayBlockingQueue<String> buffer = new ArrayBlockingQueue<String>(5); static CountDownLatch latch = new CountDownLatch(15); class Productor extends Thread { int quality; Productor(int quality){ this.quality = quality; } @Override public void run(){ while(quality > 0){ try { product(); } catch (InterruptedException e) { e.printStackTrace(); quality++; } quality--; } latch.countDown(); } public void product() throws InterruptedException{ String str = StringUtils.getRandomString(10); buffer.put(str); System.out.println(this.getName() + " product " + str); } } class Customer extends Thread { int quality; Customer(int quality){ this.quality = quality; } @Override public void run(){ while(quality > 0){ try { consume(); } catch (InterruptedException e) { e.printStackTrace(); quality++; } quality--; } latch.countDown(); } public void consume() throws InterruptedException{ String str = buffer.take(); System.out.println(this.getName() + " cusume " + str); } } /** * @param args * @throws InterruptedException */ public static void main(String[] args) throws InterruptedException { long startTime = System.nanoTime(); MutiProductorAndCustomer demo = new MutiProductorAndCustomer(); for(int i =0 ; i< 10; i++){ Thread t1 = demo.new Productor(100); t1.start(); } for(int i =0 ; i< 5; i++){ Thread t2 = demo.new Customer(200); t2.start(); } latch.await(); long endTime = System.nanoTime(); System.out.println(endTime - startTime); } }
字符串随机生成器StringUtils
package com.xx.pub; import java.util.Random; public class StringUtils { public static String getRandomString(int length) { //length表示生成字符串的长度 String base = "abcdefghijklmnopqrstuvwxyz0123456789"; Random random = new Random(); StringBuffer sb = new StringBuffer(); for (int i = 0; i < length; i++) { int number = random.nextInt(base.length()); sb.append(base.charAt(number)); } return sb.toString(); } }
jdk 1.5+ 采用信号量实现
使用了3个信号量,mutex用来控制对临界缓冲区的访问,slots标识空闲的缓冲区,items标识已装入的缓冲区。如果使用ConcurrentLinkedQueue做缓冲区的话,互斥信号量mutex可以不用。
package com.xx.concurrent.commonUse;
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Semaphore;
public class ProductorAndCustomerWithSemaphore {
//此处使用的是非线程安全LinkedList
Queue<String> buffer = new LinkedList<String>();
//使用ConcurrentLinkedQueue的话,互斥信号量mutex可以不用,可以提高一定的性能
//Queue<String> buffer = new ConcurrentLinkedQueue<String>();
static int BUFFERSIZE = 10;
//线程数量
static CountDownLatch latch = new CountDownLatch(15);
static Semaphore mutex = new Semaphore(1);
static Semaphore slots = new Semaphore(BUFFERSIZE);
static Semaphore items = new Semaphore(0);
class Productor extends Thread {
int quality;
Productor(int quality){
this.quality = quality;
}
@Override
public void run(){
while(quality > 0){
try {
slots.acquire();
mutex.acquire();
product();
mutex.release();
items.release();
} catch (InterruptedException e) {
e.printStackTrace();
quality++;
}
quality--;
}
latch.countDown();
}
public void product() throws InterruptedException{
String str = StringUtils.getRandomString(10);
buffer.offer(str);
System.out.println(this.getName() + " product " + str);
}
}
class Customer extends Thread {
int quality;
Customer(int quality){
this.quality = quality;
}
@Override
public void run(){
while(quality > 0){
try {
items.acquire();
mutex.acquire();
consume();
mutex.release();
slots.release();
} catch (InterruptedException e) {
e.printStackTrace();
quality++;
}
quality--;
}
latch.countDown();
}
public void consume() throws InterruptedException{
String str = buffer.poll();
System.out.println(this.getName() + " cusume " + str);
}
}
/**
* @param args
* @throws InterruptedException
*/
public static void main(String[] args) throws InterruptedException {
long startTime = System.nanoTime();
ProductorAndCustomerWithSemaphore demo = new ProductorAndCustomerWithSemaphore();
for(int i =0 ; i< 10; i++){
Thread t1 = demo.new Productor(100);
t1.start();
}
for(int i =0 ; i< 5; i++){
Thread t2 = demo.new Customer(200);
t2.start();
}
latch.await();
long endTime = System.nanoTime();
System.out.println(endTime - startTime);
}
}
性能比较:
jdk1.5- wait() & notify()
111658991ns
jdk1.5+ ArrayBlockingQueue
98588747ns
jdk1.5+ Semaphore 使用线程不安全的buffer linkedList
123800982ns
jdk1.5+ Semaphore 使用线程不安全的buffer ConcurrentLinkedQueue
110885827ns
可以看出使用BlockQueue来实现生产者和消费者问题,性能最好。