(五)Lock锁的用法||Lock锁与 synchronized 关键字的区别

来源:互联网 发布:c stl程序员开发指南 编辑:程序博客网 时间:2024/05/25 01:34

Lock锁的用法

Lock锁机制与 synchronized 关键字的区别


一、Lock锁的用法

Lock lock = new ReentrantLock();
lock.lock();
try{
//可能会出现线程安全的操作
}finally{
//一定在finally中释放锁
//也不能把获取锁在try中进行,因为有可能在获取锁的时候抛出异常
lock.unlock();
}

二、Lock锁机制与 synchronized 关键字的区别

  1. synchronized修饰的同步代码块其实自身是具有自动上锁、自动解锁功能的;
    Lock锁机制则是手动解锁,手动上锁的;

  2. 用synchronized修饰的同步代码块还有同步方法是有同步锁对象的;
    Lock锁机制是没有同步锁对象的;

  3. 因为synchronized修饰的同步代码块还有同步方法是具有锁对象的,因此,可以
    调用notify()、wait()、notifyAll()的方法;

    但是因为Lock锁机制是不具有锁对象的,因此是不可以去调用notify()、wait()、
    notifyAll()方法的;
    那么如果Lock锁机制一定要使用等待唤醒机制的话,在Java5之后,我们只能通过创建一个Condition类对象,然后通过该对象来调用await()、signal()、signAll()方法,而这几个方法的作用跟notify()、wait()、notifyAll()是一样功能的;

三、Condition用法

Condition的功能类似于在传统的线程技术中的Object.wait()和Object.notify()的功能。

Condition condition = lock.newCondition();
user. condition.await(); 类似wait
user. Condition. Signal() 类似notify

四、代码示例

共享资源源实体类

/** 共享资源源实体类 */class UserInfo {    public String userSex;    public String userName;    /**手动lock锁*/    Lock lock= new ReentrantLock();    /**Condition功能*/    Condition condition=lock.newCondition();    /**线程通讯标识     * true:让生产者进行等待,消费者进行消费     * false:生产者可以生产,消费者进行等待     * */    public boolean flag=false;}

输入线程资源

public class InputThread extends Thread{    private UserInfo user;    //构造函数    public InputThread (UserInfo user){        this.user=user;    }    @Override    public void run() {        int count=0;            while (true){                //开始手动上锁                user.lock.lock();                try {                    //当flag为true时(注意:在判断条件里if(user.flag)等价于if(user.flag==true))                    if (user.flag) {                        //让当前线程 从运行状态变为休眠状态,并且释放锁的资源                        user.condition.await();                    }                    //1.当线程第一次运行时,flag为false,先进行生产                    if(count==0){                            user.userName="大圣";                            user.userSex="男";                        }else{                            user.userName="小红";                            user.userSex="女";                        }                    //计算奇数或者偶数公式                    count=(count+1)%2;                    //2.当第一个线程生产完的时候,把flag状态改为true,                    // 即让生产者线程处于等待状态,让消费者进行读取                    user.flag=true;                    //唤醒当前等待的线程,否则你只能打印一条                    user.condition.signal();                } catch (Exception e) {                    e.printStackTrace();                } finally {                    //手动释放锁                    user.lock.unlock();                }            }    } }

输出线程资源

public class OutputThread extends Thread{    private UserInfo user;    //构造函数    public OutputThread(UserInfo user){        this.user=user;    }    @Override    public void run() {        while (true) {            //开始手动上锁            user.lock.lock();            try {                //当flag为false时(注意:在判断条件里if(!user.flag)等价于if(user.flag==false))                if (!user.flag) {                    //让当前线程 从运行状态变为休眠状态,并且释放锁的资源                    user.condition.await();                }                //3.进来时,flag为true,消费者进行消费,生产者进行等待                System.out.println("userName:"+user.userName+"----userSex:"+user.userSex);                //4.消费者读取完后,把flag状态改为false,再去生产者那边生产,待在消费者这里也没用                user.flag=false;                //唤醒当前等待的线程,否则你只能打印一条                user.condition.signal();            } catch (Exception e) {                e.printStackTrace();            } finally {                //手动释放锁                user.lock.unlock();            }        }    }}

运行代码:

 UserInfo user=new UserInfo();        //构造方法就是在这里用的        //两个线程共享同一变量        InputThread it=new InputThread(user);        OutputThread ot=new OutputThread(user);        it.start();        ot.start();

运行结果:
这里写图片描述