Java两种常见锁的实现

互斥锁:互斥锁是⼀种最常⻅的锁类型,⽤于实现互斥访问共享资源。在任何时刻,只有⼀个线程可以持有互斥锁,其他线程必须等待直到锁被释放。这确保了同⼀时间只有⼀个线程能够访问被保护的资源。

互斥锁的实现:

  1. Java提供了synchronized关键字,允许你在对象上创建一个监视器锁或锁定代码块,以确保同时只有一个线程能够执行该代码块的内容。
public class Counter {
    private int count = 0;
    
    // 使用synchronized关键字标记方法,确保线程安全
    public synchronized void increment() {
        count++;
    }
    
    // 获取当前计数值
    public int getCount() {
        return count;
    }
}

在上面的例子中,通过将increment方法声明为synchronized,我们确保了任何时刻都只有一个线程可以访问这个方法。这个方法是互斥的,因此可以安全地在多线程环境中更新共享资源count。

public class Counter {
    private final Object lock = new Object(); // 创建一个锁对象
    private int count = 0;
    
    public void increment() {
        synchronized(lock) { // 进入同步代码块,锁定lock对象
            count++;
        }
    }
    
    public int getCount() {
        return count;
    }
}

在这个例子中,用一个专门的私有锁对象lock来创建互斥效果。进入synchronized块时,线程会在lock对象上获得锁,退出时释放锁,从而确保count++的线程安全。

  1. Java的java.util.concurrent.locks包提供了一些更高级和灵活的锁实现,包括ReentrantLock。这种锁还提供了一些附加的功能和特性,如尝试锁定、定时锁定和中断等待锁的线程的能力。
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Counter {
    private final Lock lock = new ReentrantLock(); // 创建一个ReentrantLock实例
    private int count = 0;
    
    public void increment() {
        lock.lock(); // 获取锁
        try {
            count++;
        } finally {
            lock.unlock(); // 确保释放锁
        }
    }
    
    public int getCount() {
        return count;
    }
}

⾃旋锁:⾃旋锁是⼀种基于忙等待的锁,即线程在尝试获取锁时会不断轮询,直到锁被释放。

  1. 在Java中,实现自旋锁可以通过循环和volatile变量来简单实现。volatile关键字确保了变量的可见性,即在一个线程中修改了该变量的值,那么在其他线程中可以立即得知这个修改。
public class SpinLock {
    private volatile boolean isLocked = false;

    public void lock() {
        while (isLocked) {
            // 循环等待,直到锁被释放
            // 注意:在实际应用中,这里可以添加让出CPU执行权的操作,如Thread.yield()
        }
        isLocked = true;
    }

    public void unlock() {
        isLocked = false;
    }
}

上面这个简单的自旋锁实现有一些潜在问题。最明显的是,这个锁不是公平的,也就是说,等待获取锁的线程可能会遇到饥饿现象,尤其是在高负载的情况下。另外,如果不加以控制,lock方法可能会在单核处理器系统上引起问题,因为它可能会导致永久自旋,从而阻塞其他线程的执行。

  1. 为了解决上述实现中的问题,提高自旋锁的效率,并且避免公平性问题,我们可以利用Java的java.util.concurrent.atomic包中提供的原子类进行改进。下面是使用AtomicBoolean实现的自旋锁示例:
import java.util.concurrent.atomic.AtomicBoolean;

public class SpinLock {
    private AtomicBoolean lock = new AtomicBoolean(false);

    public void lock() {
        while (true) {
            // 尝试从false设置为true,如果成功,则获得锁
            if (!lock.getAndSet(true)) {
                return;
            }
            // 否则循环继续等待
            // 在实际使用中,根据需要可能会加入Thread.yield()或者Thread.sleep()减少CPU使用率
        }
    }

    public void unlock() {
        lock.set(false);
    }
}

通过使用AtomicBoolean的getAndSet方法,我们可以安全地检查当前锁状态,并且仅在锁未被占用时(即值为false时)将其设为true来获得锁。这个方法是原子的,即检查和设置值的操作是作为一个不可分割的整体执行的,因此可以安全使用在并发编程中。

  • 24
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
### 回答1: 对于分布式Java提供了一种称为Java并发库的API,可以帮助程序员实现分布式Java并发库提供了一个可重入(ReentrantLock),它可以帮助程序员实现分布式。此外,还可以使用Java中的读写(ReadWriteLock)实现分布式。 ### 回答2: Java 可以通过一些常见的技术实现分布式。主要有以下几种方法: 1. 基于数据库的:可以使用数据库的机制来实现分布式。在多个客户端同时访问数据库时,可以通过事务来确保只有一个客户端能够成功获取,并进行相关操作。 例如,在数据库中创建一个表,用于存储的信息。当需要获取时,通过执行一个带有唯一约束的 SQL 语句来插入记录,如果插入成功,表示获取到了,否则表示已被其他客户端持有。 2. 基于缓存的:使用分布式缓存来实现机制,常见的分布式缓存工具有 Redis、Memcached 等。通过缓存中的原子操作,如 setnx(set if not exists) 操作来实现的获取与释放。 例如,使用 Redis 的 setnx 命令来设置一个带有过期时间的 key,如果设置成功,表示获取到了,执行相应的业务逻辑;否则表示已被其他客户端持有。 3. 基于 ZooKeeper 的:ZooKeeper 是一个开源的分布式协调服务,可以用于实现分布式。通过创建临时有序节点来表示的拥有权,并利用 ZooKeeper 对节点的操作的顺序性和原子性来实现的获取与释放。 例如,每个客户端在 ZooKeeper 上创建一个唯一的临时有序节点,如果创建的节点是当前最小的节点,表示获取到了,执行相应的业务逻辑;否则监听上一个节点的变化事件来等待的释放。 以上方法都可以用来实现分布式,选择哪一种方法主要根据具体的业务需求、系统架构和可用资源来进行选择。 ### 回答3: Java实现分布式有多种方式,下面我将介绍其中两种常见的方法。 1. 基于数据库实现分布式: - 创建一个唯一的键标识,用于表示加资源。可以使用数据库表的主键或者自定义的唯一标识。 - 在获取之前,先尝试向数据库插入一条记录,利用数据库的唯一约束来保证只有一个线程能够插入成功,表示获取到了。 - 在释放时,删除该记录,释放资源。 2. 基于缓存实现分布式: - 使用分布式缓存,例如Redis,作为的存储介质。 - 在获取之前,使用Redis的setnx命令设置一个键值对,将键设为加的资源标识,值设为当前时间戳。 - 如果设置成功,表示获取到了;如果设置失败,表示已经被其他线程占用。 - 在释放时,使用Redis的del命令删除该键值对,释放资源。 以上两种方法都是基于标识符来实现的,通过标识符判断是否获取到了资源。使用数据库或者缓存来存储信息,保证了分布式系统的多个节点之间可以共享状态。需要注意的是,分布式实现还需要考虑到的超时时间、的可重入性、死的避免等问题,以确保的正确性和可靠性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

miss writer

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值