java 线程锁Lock

说明

本博客每周五更新一次。
最近一次开发中使用多线程,过去常用synchronized,基于jvm实现,代码简答,可控性弱,高并发场景效率相对较低,以后尽量多用Lock实现。
Lock实现开始于java 1.5,java.util.concurrent.locks包下Lock和ReadWriteLock是两种类型锁的根接口。

分享

资料

synchronized与Lock对比

  1. synchronized不需要用户去手动释放锁,Lock需要使用者主动释放锁,否则会造成造成死锁。
  2. synchronized锁因为等待IO或sleep等愿意被阻塞,其他线程只能一直等待,Lock可设置等待时间。
  3. 多线程写操作会造成数据异常,读操作不会,synchronized锁不区分读写,限制单线程操作。Lock的ReentrantReadWriteLock支持读写区别管理,多线程(共享锁)读取,单线程(排他锁)写入,效率更高。
  4. synchronized无法判断线程是否成功获取到锁,Lock可获取锁状态。

Lock

Lock 接口方法

方法说明
void lock()获取锁,如果已被其他线程获取,则等待。
void lockInterruptibly()获取锁,如果已被其他线程获取,可调用interrupt()中断等待
Condition newCondition()返回绑定到此 Lock的新的Condition实例,用于线程间通信。
boolean tryLock()尝试获取该锁,返回状态
boolean tryLock(long time, TimeUnit unit)设定时间内尝试获取该锁,返回状态
void unlock()释放锁

实现类 ReentrantLock

  • ReentrantLock为可重入锁,也是唯一实现Lock接口的类,可指定锁类型为 true 公平锁和 false 非公平锁,默认false非公平锁,使用实例如下:
import java.util.concurrent.locks.Lock;  
import java.util.concurrent.locks.ReentrantLock;
public class LockThread {

    //创建锁对象
    Lock lock = new ReentrantLock(); //不指定布尔类型,默认非公平锁

    //同步方法
    public void lock(String name) {  
        // 获取锁  
        lock.lock();  
        try {  
            System.out.println(name + " get the lock");  
            
        //lock() 必须释放锁,否则会堵塞,tryLock()尝试获取锁,并响应锁状态。
        } finally {  
            // 释放锁  
            lock.unlock();  
            System.out.println(name + " release the lock");  
        }  
    }  

    public static void main(String[] args) {
        LockThread lt = new LockThread();  
        new Thread(() -> lt.lock("A")).start();  
        new Thread(() -> lt.lock("B")).start();  
    }
}

ReadWriteLock

ReadWriteLock 接口方法

ReadWriteLock 维护了一对相关的锁:只读和写入。没有 writer时,读取锁可由多个 reader 线程同时操作,当有writer时,写入锁排他,读取操作挂起。

方法说明
Lock readLock()获取读操作锁
Lock writeLock()获取写操作锁

实现类 ReentrantReadWriteLock

  • 代码实例,三个线程同时读写一个共享数据
import java.util.Random;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

class Queue {
    //共享数据,只能有一个线程能写该数据,但可以有多个线程同时读该数据。
    private Object data = null;

    //创建锁对象
    ReadWriteLock lock = new ReentrantReadWriteLock();
    Lock read=lock.readLock();  //读取锁
    Lock write=lock.writeLock(); //写入锁

    // 读数据
    public void get() {
        // 加读锁
        read.lock();
        try {
            System.out.println(Thread.currentThread().getName() + " be ready to read data!");
            Thread.sleep((long) (Math.random() * 1000)); //随机时间挂起
            System.out.println(Thread.currentThread().getName() + " have read data :" + data);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 释放读锁
            read.unlock();
        }
    }

    // 写数据
    public void put(Object data) {
        // 加写锁
        write.lock();
        try {
            System.out.println(Thread.currentThread().getName() + " be ready to write data!");
            Thread.sleep((long) (Math.random() * 1000));  //随机时间挂起
            this.data = data;
            System.out.println(Thread.currentThread().getName() + " have write data: " + data);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 释放写锁
            write.unlock();
        }

    }
}

public class ReadWriteLockDemo {
    public static void main(String[] args) {

        final Queue queue = new Queue();

        //一共启动6个线程,3个读线程,3个写线程
        for (int i = 0; i < 3; i++) {
            //读线程
            new Thread() {
                public void run() {
                    while (true) {
                        queue.get();
                    }
                }

            }.start();

            //写线程
            new Thread() {
                public void run() {
                    while (true) {
                        queue.put(new Random().nextInt(10000));
                    }
                }
            }.start();
        }
    }
}

总结

  • 多线程一般用于提高效率,增加单位时间处理能力,设计上功能模块化,避免功能重叠,造成逻辑复杂,给自己挖坑,增加开发难度。
  • 从功能可用,到实现功能且执行高效,到差异化可复用实现功能,逐步提升自我要求,技术没有最好,只有更好,加油。
  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值