Java中的Lock接口,比起synchronized,优势在哪里?

如果需要实现一个高效的缓存,它允许多个用户读,但只允许一个用户写,一次来保证它的完整性,该如何实现?

Lock接口在多线程和并发编程中最大的优势是它们分别为读和写提供了锁。

       读写锁ReentrantReadWriteLock,它表示有两个锁,一个是读操作相关的锁,也称为共享锁;另一个是写操作相关的锁,也叫排他锁。“读写”、“写读”、和 “写写“ 都是互斥的;而 ”读读“ 是异步的,非互斥的。

即:多个线程可以同时进行读取操作,但是同一时刻只允许一个线程进行写入操作。

本题目就可以使用读写锁ReentrantReadWriteLock来实现。

“读读共享”例子:

package com.learn.ReentrantReadWriteLockTest;

import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * 读读共享
 */
public class ReadWriteLockTest1 {
    public static void main(String[] args) {
        Service service = new Service();
        ThreadA a = new ThreadA(service);
        a.setName("A");
        ThreadB b = new ThreadB(service);
        b.setName("B");
        a.start();
        b.start();
    }

}
class Service{
    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    public void read(){
        try{
            lock.readLock().lock();
            System.out.println("获得读锁:"+Thread.currentThread().getName()+" "+System.currentTimeMillis());
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }finally{
            lock.readLock().unlock();
        }
    }
}

class ThreadA extends Thread{
    private Service service;

    public ThreadA(Service service){
        this.service = service;
    }

    @Override
    public void run() {
        super.run();
        service.read();
    }
}

class ThreadB extends Thread{
    private Service service;

    public ThreadB(Service service){
        this.service = service;
    }

    @Override
    public void run() {
        super.run();
        service.read();
    }
}

"写写互斥"例子:

package com.learn.ReentrantReadWriteLockTest;

import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * 写写互斥
 */
public class ReadWriteLockTest2 {
    public static void main(String[] args) {
        Service2 service2 = new Service2();
        ThreadA2 a = new ThreadA2(service2);
        a.setName("A");
        ThreadB2 b = new ThreadB2(service2);
        b.setName("B");
        a.start();
        b.start();
    }

}
class Service2{
    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    public void write(){
        try{
            lock.writeLock().lock();
            System.out.println("获得写锁:"+Thread.currentThread().getName()+" "+System.currentTimeMillis());
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }finally{
            lock.writeLock().unlock();
        }
    }
}

class ThreadA2 extends Thread{
    private Service2 service;

    public ThreadA2(Service2 service){
        this.service = service;
    }

    @Override
    public void run() {
        super.run();
        service.write();
    }
}

class ThreadB2 extends Thread{
    private Service2 service;

    public ThreadB2(Service2 service){
        this.service = service;
    }

    @Override
    public void run() {
        super.run();
        service.write();
    }
}

“读写互斥”例子:

package com.learn.ReentrantReadWriteLockTest;

import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * 读写互斥
 */
public class ReadWriteLockTest3 {
    public static void main(String[] args) {
        Service3 service3 = new Service3();
        ThreadA3 a = new ThreadA3(service3);
        a.setName("A");
        ThreadB3 b = new ThreadB3(service3);
        b.setName("B");
        b.start();
        a.start();
    }

}
class Service3{
    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    public void read(){
        try{
            lock.readLock().lock();
            System.out.println("获得读锁 "+Thread.currentThread().getName()+" "+System.currentTimeMillis());
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }finally{
            lock.readLock().unlock();
        }
    }

    public void write(){
        try{
            lock.writeLock().lock();
            System.out.println("获得写锁 "+Thread.currentThread().getName()+" "+System.currentTimeMillis());
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }finally{
            lock.writeLock().unlock();
        }
    }
}

class ThreadA3 extends Thread{
    private Service3 service;

    public ThreadA3(Service3 service){
        this.service = service;
    }

    @Override
    public void run() {
        super.run();
        service.read();
    }
}

class ThreadB3 extends Thread{
    private Service3 service;

    public ThreadB3(Service3 service){
        this.service = service;
    }

    @Override
    public void run() {
        super.run();
        service.write();
    }
}

“写读互斥”例子:

package com.learn.ReentrantReadWriteLockTest;

import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * 读写互斥
 */
public class ReadWriteLockTest3 {
    public static void main(String[] args) {
        Service3 service3 = new Service3();
        ThreadA3 a = new ThreadA3(service3);
        a.setName("A");
        ThreadB3 b = new ThreadB3(service3);
        b.setName("B");
        b.start();
        a.start();
    }

}
class Service3{
    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    public void read(){
        try{
            lock.readLock().lock();
            System.out.println("获得读锁 "+Thread.currentThread().getName()+" "+System.currentTimeMillis());
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }finally{
            lock.readLock().unlock();
        }
    }

    public void write(){
        try{
            lock.writeLock().lock();
            System.out.println("获得写锁 "+Thread.currentThread().getName()+" "+System.currentTimeMillis());
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }finally{
            lock.writeLock().unlock();
        }
    }
}

class ThreadA3 extends Thread{
    private Service3 service;

    public ThreadA3(Service3 service){
        this.service = service;
    }

    @Override
    public void run() {
        super.run();
        service.read();
    }
}

class ThreadB3 extends Thread{
    private Service3 service;

    public ThreadB3(Service3 service){
        this.service = service;
    }

    @Override
    public void run() {
        super.run();
        service.write();
    }
}

如果需要实现一个高效的缓存,它允许多个用户读,但只允许一个用户写,一次来保证它的完整性,该如何实现?代码如下:

package com.learn.ReentrantReadWriteLockTest;

import java.util.Random;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadWriteLockTest5 {
    public static void main(String[] args) {
        ReadWrite readWrite = new ReadWrite();
        //创建3个写线程
        for (int i=0;i<3;i++){
            ThreadWrite write = new ThreadWrite(readWrite,new Random().nextInt(100));
            write.setName("write"+i+":");
            write.start();
        }
        //创建3个读线程
        for (int i=0;i<3;i++){
            ThreadRead read = new ThreadRead(readWrite);
            read.setName("read"+i+":");
            read.start();
        }

    }
}

class ReadWrite{
    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    private Object data=null;
    public void read(){
        try{
            lock.readLock().lock();
            try {
                System.out.println(Thread.currentThread().getName()+"is ready to read");
                Thread.sleep(new Random().nextInt(100));
                System.out.println(Thread.currentThread().getName()+"have read date "+data);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }finally{
            lock.readLock().unlock();
        }
    }

    public void write(Object data){
        try{
            lock.writeLock().lock();
            try {
                System.out.println(Thread.currentThread().getName()+"is ready to write");
                this.data = data;
                Thread.sleep(new Random().nextInt(100));
                System.out.println(Thread.currentThread().getName()+"have write date "+data);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }finally{
            lock.writeLock().unlock();
        }
    }
}

class ThreadRead extends Thread{
    private ReadWrite readWrite;

    public ThreadRead(ReadWrite readWrite){
        this.readWrite = readWrite;
    }

    @Override
    public void run() {
        super.run();
        //while(true){
            readWrite.read();
        //}

    }
}

class ThreadWrite extends Thread{
    private ReadWrite readWrite;
    private Object data;


    public ThreadWrite(ReadWrite readWrite,Object data){
        this.readWrite = readWrite;
        this.data = data;
    }

    @Override
    public void run() {
        super.run();
        //while(true){
            readWrite.write(data);
        //}
    }
}


### Java并发编程中的Lock接口synchronized关键字 #### 锁机制的基础概念 Java提供了多种方式来处理线程同步问题,`synchronized` 关键字自早期版本就已存在并支持线程同步操作[^1]。另一方面,`java.util.concurrent.locks.Lock` 接口是在较新的Java版本中引入的一种更灵活的锁定抽象。 #### synchronized的关键特性 `synchronized` 是一种内置的语言级功能,用于控制多个线程对共享资源的访问。当方法或代码块被声明为 `synchronized` 时,同一时刻只有一个线程可以执行该部分代码。这确保了即使有其他线程试图进入同一个对象上的另一个 `synchronized` 方法或代码段,也必须等待当前持有锁的线程完成其工作并释放锁之后才能继续。 此外,在任何线程进入由相同监视器保护的 `synchronized` 块之前,都会看到所有先前受此监视器保护修改的效果[^2]。 ```java public class Counter { private int count; public synchronized void increment() { this.count++; } } ``` #### Lock接口优势 相比之下,`Lock` 接口提供了一种显式的加锁/解锁机制,并允许更加复杂的锁定协议。通过使用 `Lock` 实现类(如 ReentrantLock),可以获得比传统 `synchronized` 更强大的功能: - **可中断的获取锁**:尝试获得锁的过程中如果接收到中断信号,则立即返回失败而不是一直阻塞下去。 - **超时获取锁**:可以在指定时间内尝试获取锁;若未能成功则放弃而不至于无限期挂起。 - **公平性选项**:可以选择是否按照请求顺序授予锁给下一个等待者。 - **多条件变量的支持**:一个 `Lock` 可关联多个不同的条件实例,从而实现更为精细的通知逻辑。 下面是一个简单的例子展示了如何利用 `ReentrantLock` 来替代传统的 `synchronized` 方式: ```java import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.Condition; class BoundedBuffer { final ReentrantLock lock = new ReentrantLock(); final Condition notFull = lock.newCondition(); final Condition notEmpty = lock.newCondition(); final Object[] items = new Object[100]; int putptr, takeptr, count; public void put(Object x) throws InterruptedException { lock.lock(); try { while (count == items.length) notFull.await(); items[putptr] = x; if (++putptr == items.length) putptr = 0; ++count; notEmpty.signal(); } finally { lock.unlock(); } } public Object take() throws InterruptedException { lock.lock(); try { while (count == 0) notEmpty.await(); Object x = items[takeptr]; if (++takeptr == items.length) takeptr = 0; --count; notFull.signal(); return x; } finally { lock.unlock(); } } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值