JAVA 多线程 synchronized与ReentrantLock

采用生产者消费者模型来讲解

生产者消费者

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作用的对象是一个静态方法或一个类,则它取得的锁是对类,该类所有对象同一把锁。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值