Lock的使用

在 Java 里,Lock接口是自 JDK 1.5 起引入的用于实现线程同步的工具,它为开发者提供了比synchronized关键字更为灵活的锁操作方式。下面为你详细介绍Lock相关的知识和具体用法:

1. 核心接口与实现类

  • Lock 接口:定义了锁操作的基本方法,像获取锁(lock())、尝试获取锁(tryLock())以及释放锁(unlock())等。
  • ReentrantLock:可重入锁的实现,支持公平锁和非公平锁两种模式。
  • ReentrantReadWriteLock:读写锁实现,能分离读锁和写锁,读锁可被多个线程共享,而写锁具有排他性。
  • StampedLock:JDK 8 新增的锁,支持乐观读锁、悲观读锁和写锁三种模式。

2. 相较于 synchronized 的优势

  • 灵活的锁获取方式:可以使用tryLock()尝试获取锁,还能设置超时时间。
  • 可中断的锁获取:通过lockInterruptibly()方法,在等待锁的过程中可以中断线程。
  • 条件变量支持:借助newCondition()方法生成条件对象,实现更精细的线程等待与唤醒操作。
  • 公平锁选项:能够选择公平锁,保证线程获取锁的顺序性。

3. 基础用法示例

(1)ReentrantLock 的使用
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Counter {
    private final Lock lock = new ReentrantLock();
    private int count = 0;

    public void increment() {
        lock.lock(); // 获取锁
        try {
            count++;
        } finally {
            lock.unlock(); // 释放锁
        }
    }

    public int getCount() {
        lock.lock();
        try {
            return count;
        } finally {
            lock.unlock();
        }
    }
}
(2)tryLock () 的使用
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class TryLockExample {
    private final Lock lock = new ReentrantLock();

    public void performTask() {
        if (lock.tryLock()) { // 尝试获取锁
            try {
                // 执行关键操作
                System.out.println("获取到锁,执行任务");
            } finally {
                lock.unlock();
            }
        } else {
            // 处理无法获取锁的情况
            System.out.println("未获取到锁,执行其他操作");
        }
    }
}
(3)ReentrantReadWriteLock 的使用
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class Cache {
    private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
    private String data;

    public String read() {
        rwLock.readLock().lock(); // 获取读锁
        try {
            return data;
        } finally {
            rwLock.readLock().unlock();
        }
    }

    public void write(String newData) {
        rwLock.writeLock().lock(); // 获取写锁
        try {
            data = newData;
        } finally {
            rwLock.writeLock().unlock();
        }
    }
}
(4)StampedLock 的使用
import java.util.concurrent.locks.StampedLock;

public class Point {
    private double x, y;
    private final StampedLock lock = new StampedLock();

    public double distanceFromOrigin() {
        long stamp = lock.tryOptimisticRead(); // 尝试乐观读
        double currentX = x, currentY = y;
        if (!lock.validate(stamp)) { // 验证读期间是否有写操作
            stamp = lock.readLock(); // 获取悲观读锁
            try {
                currentX = x;
                currentY = y;
            } finally {
                lock.unlockRead(stamp);
            }
        }
        return Math.hypot(currentX, currentY);
    }

    public void move(double deltaX, double deltaY) {
        long stamp = lock.writeLock(); // 获取写锁
        try {
            x += deltaX;
            y += deltaY;
        } finally {
            lock.unlockWrite(stamp);
        }
    }
}

4. 条件变量(Condition)的使用

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class BoundedQueue {
    private final Lock lock = new ReentrantLock();
    private final Condition notFull = lock.newCondition();
    private final Condition notEmpty = lock.newCondition();
    private final Object[] items;
    private int count, head, tail;

    public BoundedQueue(int capacity) {
        items = new Object[capacity];
    }

    public void enqueue(Object x) throws InterruptedException {
        lock.lock();
        try {
            while (count == items.length)
                notFull.await(); // 队列满时等待
            items[tail] = x;
            if (++tail == items.length)
                tail = 0;
            count++;
            notEmpty.signal(); // 通知队列非空
        } finally {
            lock.unlock();
        }
    }

    public Object dequeue() throws InterruptedException {
        lock.lock();
        try {
            while (count == 0)
                notEmpty.await(); // 队列空时等待
            Object x = items[head];
            if (++head == items.length)
                head = 0;
            count--;
            notFull.signal(); // 通知队列未满
            return x;
        } finally {
            lock.unlock();
        }
    }
}

5. 公平锁与非公平锁

  • 公平锁:线程按照请求锁的顺序依次获取锁,能减少线程饥饿的情况,但可能会降低系统的吞吐量。
Lock fairLock = new ReentrantLock(true); // 创建公平锁
  • 非公平锁:线程获取锁的顺序是不确定的,吞吐量相对较高,不过可能导致某些线程长时间无法获取到锁。
Lock unfairLock = new ReentrantLock(); // 默认是非公平锁

6. 注意要点

  • 锁的释放:必须在finally块中释放锁,防止出现死锁的情况。
  • 锁的嵌套:可重入锁允许同一线程多次获取同一把锁,但要注意正确释放锁。
  • 性能考量:在竞争激烈的场景下,Lock的性能通常优于synchronized,不过在竞争不激烈的情况下,两者的性能差异并不明显。
  • 使用场景:当需要灵活的锁操作(如超时、可中断、公平性)时,应优先考虑使用Lock;而在简单的同步场景下,使用synchronized更为简洁。

7. 锁的选用建议

  • ReentrantLock:适用于需要灵活锁操作的场景,比如支持锁的中断、超时等。
  • ReentrantReadWriteLock:在读多写少的场景下能显著提升性能。
  • StampedLock:在读多写少且对读性能要求极高的场景中使用,不过它的使用方式相对复杂。

通过合理运用Lock接口及其实现类,能够更精细地控制线程同步,从而提升多线程程序的性能和可靠性。

WakeLock是Android中的一个机制,用于控制设备的唤醒状态。通过使用WakeLock,应用程序可以防止设备进入休眠状态,从而保持屏幕常亮。 在Android中,有几种方式可以使用WakeLock。其中包括以下几种常用方法: 1. 使用PowerManager类:可以通过PowerManager类来获取WakeLock对象,并使用acquire()和release()方法来控制设备的唤醒状态。这种方式需要申请WAKE_LOCK权限。 2. 在Window设置flag:可以使用WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON标志来设置窗口的保持唤醒状态。这种方式不需要申请权限,并且可以通过在Window的布局xml文件中的顶层布局添加android:keepScreenOn="true"属性来达到相同的效果。 3. 使用WakefulBroadcastReceiver:这是一种特殊的广播接收器,可以使用它来获取WakeLock对象,并在接收到广播时启用唤醒状态。这种方式适用于特定的场景,例如在接收到特定的广播消息时保持设备唤醒状态。 根据具体的需求和使用场景,可以选择适合的WakeLock使用方法。以上是其中几种常见的方法,可以根据需要选择合适的方式来控制设备的唤醒状态。<span class="em">1</span><span class="em">2</span> #### 引用[.reference_title] - *1* *2* [WakeLock使用](https://blog.youkuaiyun.com/zmm911zmm/article/details/103134442)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值