大白话理解,快速拿下JUC(五)

1、悲观锁和乐观锁

        悲观锁:是不支持并发的,只能一个操作完后另一个再操作,频繁的上锁解锁,效率低但数据安全

        乐观锁:支持并发,可以多个同时操作,但是引入了版本号概念,如果拿到的版本号和数据库的版本号不一致则操作失败,如A和B线程同时去修改余额,A先提交,那么版本号由v1.0改为v1.1后,B再次提交则匹配不上所以提交失败,下图可分别展示两个锁的区别

 2、表锁和行锁

        表锁:就是将整张表进行上锁,其余线程不能进行操作,其效率较低,但不会存在死锁问题

        行锁:比如表里有四条数据,锁第一条数据叫行锁,行锁效率快但会存在存在互相等待死锁

3、读锁和写锁

        读锁:也叫共享锁,可以多个线程同时访问一个数据,会发生死锁问题,比如A线程修改时候需要等B读完之后,B线程修改时候需要等A读完之后,可能造成互相等待的死锁问题

        写锁:也叫独占锁,同一个数据只能一个线程写操作,也会存在死锁问题,比如A写完第一个条数据后去写第二个数据,B线程写完第二个数据后去写第一个数据,互相都没有释放其锁,造成互相等待死锁问题

        总结:一个资源可以被多个线程访问(读锁共享锁),或者被一个线程进行写的操作(写锁独占锁),但是不能同时存在读写线程,读写互斥,读读共享

4、读写锁案例

        使用ReadWriteLock的实现类ReentrantReadWriteLock,可以实现线程安全的读写操作,原理还是上锁机制,先写入再读取机制       

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class lockDemo01 {
    public static void main(String[] args) {
        mapLock mapLock=new mapLock();
        for (int i = 1; i <=5 ; i++) {
            final int number = i;
            new Thread(()->{
                try {
                    mapLock.put(number+"",number+"");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            },String.valueOf(i)).start();
        }
        for (int i = 1; i <=5 ; i++) {
            final int number = i;
            new Thread(()->{
                try {
                    mapLock.get(number+"");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            },String.valueOf(i)).start();
        }
    }
}
class mapLock{
    private volatile Map<String,Object> map=new HashMap<>();

    ReadWriteLock readWriteLock=new ReentrantReadWriteLock();
    public void put(String key,Object obj) throws InterruptedException {
        readWriteLock.writeLock().lock();
        System.out.println(Thread.currentThread().getName()+" 即将进行写入");
        TimeUnit.MICROSECONDS.sleep(300);
        map.put(key,obj);
        System.out.println(Thread.currentThread().getName()+"写入完成:"+key);
        readWriteLock.writeLock().unlock();
    }
    public Object get(String key) throws InterruptedException {
        readWriteLock.readLock().lock();
        System.out.println(Thread.currentThread().getName()+" 即将进行取出");
        TimeUnit.MICROSECONDS.sleep(300);
        Object o = map.get(key);
        System.out.println(Thread.currentThread().getName()+"取出完成:"+key);
        readWriteLock.readLock().unlock();
        return o;
    }
}

 5、读写锁优缺点

        优点:读读共享,可以多个资源同时读取

        缺点: a、锁饥饿问题,比如有100个读的操作,一个写的操作,那么可能都忽略了写的操作。b、读时候不能写,只有读完之后才能写,写操作可以读

6、锁降级

        将写入锁降级为读锁,其流程如下图所示,其读锁不可升级为写锁

import java.util.concurrent.locks.ReentrantReadWriteLock;

public class redwirtDemo01 {
    public static void main(String[] args) {
        ReentrantReadWriteLock readWriteLock=new ReentrantReadWriteLock();
        ReentrantReadWriteLock.ReadLock red = readWriteLock.readLock();
        ReentrantReadWriteLock.WriteLock write = readWriteLock.writeLock();
        //写锁加锁
        write.lock();
        System.out.println("准备开始操作了");
        //获取读锁
        red.lock();
        System.out.println("锁降级成功");       
        //释放写锁 降级处理
        write.unlock();
        //释放读锁
        red.unlock();
    }
}

以上代码充分说明了锁降级过程,写锁可以降级为读锁,但是读锁不能升级为写锁,以下代码实验验证,经一下验证,读锁后获取不到写锁,升级成功打印不出,jvm未能结束

7、阻塞队列BlockingQueue

        阻塞队列,顾名思义,首先它是一个队列, 通过一个共享的队列,可以使得数据
由队列的一端输入,从另外一端输出;
        队列有个特点就是先进先出,就像一个双向的管道,先进去的,从另一端可以先出去,依次出去,栈的特点正好相反,是后进先出,像一个水桶,最后放进水桶的在最上边,可以第一个取到
       
        当队列是空的,从队列中获取元素的操作将会被阻塞
        当队列是满的,从队列中添加元素的操作将会被阻塞

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值