采用生产者消费者模型来讲解
生产者消费者
import java.text.SimpleDateFormat;
import java.util.Date;
public class Producer extends Thread{
private Tray tray;
private int id;
public Producer(Tray tray,int i){
this.tray=tray;
this.id=i;
}
public void run(){
for(int i=0;i<3;i++){
double x=Math.random()*10;
tray.add(x);
new String();
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())+"\t"+
currentThread().getName()+"\n\tProducer#"+this.id+" add "+String.format("%.2f", x)+" to List");
try{
sleep((int)(Math.random()*2000)); // 随机暂停0~2秒
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
}
import java.text.SimpleDateFormat;
import java.util.Date;
public class Consumer extends Thread{
private Tray tray;
private int id;
public Consumer(Tray tray,int i){
this.tray=tray;
this.id=i;
}
public void run(){
for(int i=0;i<3;i++){
double x=tray.rm();
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())+"\t"+
currentThread().getName()+"\n\tConsumer#"+this.id+" remove "+String.format("%.2f", x)+" from List");
try{
sleep((int)(Math.random()*2000));
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
}
ReentrantLock类
import java.util.ArrayList;
import java.util.concurrent.locks.*;
public class Tray {
private ArrayList<Double> list = new ArrayList<Double>();
public static final int MAX_NUM = 4;
Lock rmlock = new ReentrantLock();
Condition notempty = rmlock.newCondition();
Condition notfull = rmlock.newCondition(); // 可以有多个条件对象与同个Lock关联(不同于wait)
public synchronized void add(double d) {
rmlock.lock(); // 一旦某个线程封锁了ReentantLock对象,其余任何线程无法通过lock语句,直到第一个线程unlock
try{
while(!(list.size()<MAX_NUM)){
notfull.await();
}
list.add(d);
notempty.signalAll(); // 激活因该条件而等待的所有线程,使其由Blocked变为runnable
}catch(InterruptedException e){
e.printStackTrace();
}finally{
rmlock.unlock(); // 必须人工解锁,哪怕异常中断
}
}
public double rm() {
rmlock.lock();
double d=-1;
try{
while(!(list.size()>0)){
notempty.await();
}
d=list.remove(list.size()-1);
notfull.signalAll(); // 通知后并不会立即开始一个等待线程,仅解除阻塞以便它们待当前线程unlock后通过竞争访问对象
}catch(InterruptedException e){
e.printStackTrace();
}finally{
rmlock.unlock();
}
return d;
}
public static void main(String[] args) {
Tray t = new Tray();
for(int i=0;i<5;i++){
Producer p = new Producer(t,i+1);
Consumer c = new Consumer(t,i+1);
p.start();
c.start();
}
}
}
synchronized关键字:
public synchronized void add(double d) { // 调用该方法的Tray类实例对象被锁,直到该方法返回才解锁
while(!(list.size()<MAX_NUM)){
try{
wait(); // 解锁并使当前线程Blocked.若当前线程不是对象锁的持有者,抛出IllegalMonitorStateException
}catch(InterruptedException e){
e.printStackTrace();
}
}
list.add(d);
notifyAll(); // 解除该对象的所有Blocked线程的阻塞状态.若当前线程不是对象锁的持有者,抛错
}
public synchronized double rm() {
while(!(list.size()>0)){
try{
wait();
}catch(InterruptedException e){
e.printStackTrace();
}
}
double d=list.remove(0);
notifyAll();
return d;
}
注意:
若synchronized作用的对象是非静态的(无论加在方法上还是对象上)则它取得的锁是对象;
若synchronized作用的对象是一个静态方法或一个类,则它取得的锁是对类,该类所有对象同一把锁。