显示锁Lock

Lock接口

主要方法:

Lock与 synchronized的比较

synchronized 代码简洁(关键字,是属于语言层面实现同步)

Lock:获取锁可以被中断,超时获取锁,尝试获取锁,读多写少用读写锁(是JDK提供的一个接口,来实现同步)

可重入锁ReentrantLock

public class LockDemo {
    static Lock lock = new ReentrantLock();
    static int count;
    public void increase(int num){
        lock.lock();//获取锁
        try{
            count = count + num;
        }finally {
            lock.unlock();
        }
    }

    public synchronized void increase_syn(int num){
        count = count + num;
    }
    
    //synchronized方法调用另一个synchronized方法,可重入锁,释放锁时,一个一个释放
    public synchronized void syn2(int num){
        increase_syn(num);
    }
}

公平锁和非公平锁

如果在时间上,先对锁进行获取的请求,一定先被满足,这个锁就是公平的,不满足,就是非公平的

非公平的效率一般来讲更高

ReentrantLock默认非公平锁

ReadWriteLock

实现类:ReentrantReadWriteLock

同一时刻允许多个读线程同时访问,但是写线程访问的时候,所有的读和写都被阻塞

示例:ReentrantReadWriteLock 与 synchronized的对比

public class GoodServiceLock implements GoodService{
    private ReadWriteLock lock = new ReentrantReadWriteLock();
    private Lock readLock = lock.readLock();
    private Lock writeLock = lock.writeLock();
    private GoodInfo goodInfo;
    public GoodServiceLock(GoodInfo goodInfo){
        this.goodInfo = goodInfo;
    }

    @Override
    public GoodInfo getNum() {
        readLock.lock();
        try {
            try {
                Thread.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return goodInfo;
        }finally {
            readLock.unlock();
        }
    }

    @Override
    public void setNum(int number) {
        writeLock.lock();
        try {
            try {
                Thread.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            goodInfo.changeNumber(number);
        }finally {
            writeLock.unlock();
        }
    }
}

public class GoodServiceSyn implements  GoodService{
    private GoodInfo goodInfo;

    public GoodServiceSyn(GoodInfo goodInfo){
        this.goodInfo = goodInfo;
    }

    @Override
    public synchronized GoodInfo getNum() {
        try {
            Thread.sleep(5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return this.goodInfo;
    }

    @Override
    public synchronized void setNum(int number) {
        try {
            Thread.sleep(5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        goodInfo.changeNumber(number);
    }
}

public class GoodTest {
    private static int writeNum = 2;
    private static int readNum = 5;

    static class ReadGoodThread extends Thread {
        private GoodService goodService;

        public ReadGoodThread(GoodService goodService) {
            this.goodService = goodService;
        }

        @Override
        public void run() {
            long start = System.currentTimeMillis();
            for (int i = 0; i < 100; i++) {//操作100次
                goodService.getNum();
            }
            System.out.println(Thread.currentThread().getName() + "读取商品数据耗时:"
                    + (System.currentTimeMillis() - start) + "ms");
        }
    }

    static class WriteGoodThread extends Thread {
        private GoodService goodService;

        public WriteGoodThread(GoodService goodService) {
            this.goodService = goodService;
        }

        @Override
        public void run() {
            long start = System.currentTimeMillis();
            Random r = new Random();
            for (int i = 0; i < 10; i++) {//操作10次
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                goodService.setNum(r.nextInt(10));
            }
            System.out.println(Thread.currentThread().getName()
                    + "写商品数据耗时:" + (System.currentTimeMillis() - start) + "ms---------");

        }
    }

    public static void main(String[] args) {
        GoodInfo goodInfo = new GoodInfo(100000, 10000);
        GoodService goodsService = new GoodServiceSyn(goodInfo);
//        GoodService goodsService = new GoodServiceLock(goodInfo);
        for (int i = 0; i < writeNum; i++) {
            Thread setT = new Thread(new WriteGoodThread(goodsService));
            for (int j = 0; j < readNum; j++) {
                Thread getT = new Thread(new ReadGoodThread(goodsService));
                getT.start();
            }
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            setT.start();
        }
    }
}

运行结果:

synchronized:

Thread-23读取商品数据耗时:3112ms
Thread-7读取商品数据耗时:3655ms
Thread-19读取商品数据耗时:3749ms
Thread-9读取商品数据耗时:4055ms
Thread-21读取商品数据耗时:4033ms
Thread-11读取商品数据耗时:4195ms
Thread-15读取商品数据耗时:4330ms
Thread-17读取商品数据耗时:4820ms
Thread-1写商品数据耗时:4864ms---------
Thread-5读取商品数据耗时:5116ms
Thread-3读取商品数据耗时:5133ms
Thread-13写商品数据耗时:4991ms---------

ReentrantReadWriteLock :

Thread-5读取商品数据耗时:589ms
Thread-3读取商品数据耗时:595ms
Thread-11读取商品数据耗时:594ms
Thread-9读取商品数据耗时:608ms
Thread-7读取商品数据耗时:614ms
Thread-1写商品数据耗时:605ms---------
Thread-21读取商品数据耗时:614ms
Thread-19读取商品数据耗时:619ms
Thread-15读取商品数据耗时:641ms
Thread-23读取商品数据耗时:639ms
Thread-17读取商品数据耗时:649ms
Thread-13写商品数据耗时:589ms---------

在读多写少的场景下,可以看出ReentrantReadWriteLock比synchronized的效率高出很多。

Condition

用Lock与Condition实现消息通知(类似与Obejct的wait、notify、notifyAll,但比这个更优,不会出现信号丢失的现象,一个Lock可以创建多个Condition,根据Condition的不同,分别进行await,signal、signalAll)

public class ConditionDemo {
    static String CITY = "xianyang";
    static Lock lock = new ReentrantLock();
    static Condition siteCondition = lock.newCondition();
    static Condition kmCondition = lock.newCondition();

    private String site;
    private  int km;


    public ConditionDemo(String site, int km) {
        this.site = site;
        this.km = km;
    }

    /* 变化公里数,然后通知处于wait状态并需要处理公里数的线程进行业务处理*/
    public void changeKm(){
        lock.lock();
        try {
            this.km = 101;
            kmCondition.signal();
        }finally {
            lock.unlock();
        }
    }

    /* 变化地点,然后通知处于wait状态并需要处理地点的线程进行业务处理*/
    public  void changeSite(){
        lock.lock();
        try {
            this.site = "BeiJing";
            siteCondition.signal();
        }finally {
            lock.unlock();
        }
    }

    /*当快递的里程数大于100时更新数据库*/
    public void waitKm(){
        lock.lock();
        try {
            while(this.km<=100) {
                try {
                    kmCondition.await();
                    System.out.println("check km thread["+Thread.currentThread().getId()
                            +"] is be notifed.");
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }finally {
            lock.unlock();
        }

        System.out.println("the Km is "+this.km+",I will change db");
    }

    /*当快递到达目的地时通知用户*/
    public void waitSite(){
        lock.lock();
        try {
            while(CITY.equals(this.site)) {
                try {
                    siteCondition.await();
                    System.out.println("check site thread["+Thread.currentThread().getId()
                            +"] is be notifed.");
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }finally {
            lock.unlock();
        }
        System.out.println("the site is "+this.site+",I will call user");
    }
}

运行结果:

check km thread[11] is be notifed.
the Km is 101,I will change db
check site thread[15] is be notifed.
the site is BeiJing,I will call user
check site thread[16] is be notifed.
the site is BeiJing,I will call user
check km thread[12] is be notifed.
the Km is 101,I will change db

根据结果可知,Condition可以单独唤醒某一个或一类的线程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值