并发线程基础第四篇

目录

ReentrantLock

可重入

锁超时

公平锁

条件变量


ReentrantLock

特点

相对于synchronized它具备如下特点:

  • 可重入性: 与synchronized一样,ReentrantLock也是可重入的,同一个线程可以多次获取同一个锁,而不会造成死锁。

  • 公平性: ReentrantLock提供了公平锁和非公平锁两种锁模式。在公平模式下,锁会按照线程的请求顺序进行获取;在非公平模式下,锁不保证按照请求顺序获取。

  • 条件变量支持: ReentrantLock提供了Condition接口,可以通过Condition实现线程之间的协调和通信。

  • 可中断性: ReentrantLock提供了可中断的获取锁的方法,可以在获取锁的过程中响应中断信号。

  • 超时获取锁: ReentrantLock提供了尝试获取锁的方法,可以在指定的时间内尝试获取锁,避免长时间等待。

语法

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

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

    public void someMethod() {
        // 获取锁
        lock.lock();
        try {
            // 执行需要同步的代码块
        } finally {
            // 释放锁
            lock.unlock();
        }
    }
}

在这个语法中:

  1. 首先,我们需要导入 java.util.concurrent.locks.Lockjava.util.concurrent.locks.ReentrantLock 包。
  2. 创建一个 ReentrantLock 对象,通常将其声明为私有的静态常量。
  3. 在需要同步的方法或代码块中,首先调用 lock() 方法获取锁,然后在 try 块中执行需要同步的代码。
  4. 使用 finally 块确保无论代码是否正常执行,都会释放锁。在 finally 块中调用 unlock() 方法释放锁。
  5. lock()unlock() 之间的代码块即为需要同步的临界区。

需要注意的是,在使用ReentrantLock时,应该确保在获取锁后正确释放锁,以避免产生死锁或其他并发问题。通常建议将获取锁和释放锁的操作放在try-finally块中,以确保即使在发生异常的情况下也能正确释放锁。

 

可重入

定义

可重入(Reentrancy)指的是一个线程或进程可以再次进入自己已经持有的锁,而不会出现死锁或其他异常情况。在Java中,重入性是指同一个线程在持有锁的情况下能够再次获取该锁,而不会被自己所持有的锁所阻塞。synchronized关键字和ReentrantLock类都是可重入锁的典型代表。当一个线程已经持有了某个对象的锁时,它可以再次获取这个锁而不会被阻塞,这种机制就是可重入性的体现。

示例

public class ReentrantExample {
    public synchronized void outer() {
        inner();
    }

    public synchronized void inner() {
        System.out.println("Inner method");
    }

    public static void main(String[] args) {
        ReentrantExample example = new ReentrantExample();
        example.outer();
    }
}

可打断

定义

ReentrantLock 提供了可中断的获取锁的方法,即 lockInterruptibly() 方法。这意味着线程在等待锁的过程中,如果被其他线程中断,就会立即响应中断,并抛出 InterruptedException 异常。

示例

@Slf4j
public class Test14 {
    private static final Lock lock = new ReentrantLock();
    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            try {
                lock.lockInterruptibly();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            try {
                log.debug("获得锁");
            }finally {
                lock.unlock();
            }
        });
        log.debug("主线程获得锁");
        lock.lock();//让主线程先获得锁
        t1.start();//此时t1会一直等下去
        t1.interrupt();//打断t1,不让t1一直等下去
    }
}

锁超时

定义

ReentrantLock提供了tryLock(long time, TimeUnit unit)方法,用于尝试获取锁,在指定的时间内获取锁,如果获取成功则返回true,如果超时仍未获取到锁则返回false。通过这个方法,可以实现锁的超时等待。

示例

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

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

    public void someMethod() throws InterruptedException {
        boolean locked = false;
        try {
            // 在指定时间内尝试获取锁
            locked = lock.tryLock(5, TimeUnit.SECONDS);
            if (locked) {
                // 获取锁成功
                System.out.println("Lock acquired successfully");
                // 执行需要同步的代码块
            } else {
                // 获取锁超时
                System.out.println("Failed to acquire lock within 5 seconds");
            }
        } finally {
            if (locked) {
                // 释放锁
                lock.unlock();
            }
        }
    }
}

在这个示例中,tryLock(5, TimeUnit.SECONDS) 方法会尝试在5秒内获取锁,如果在指定时间内获取到了锁,则返回true,表示获取成功;如果超时未获取到锁,则返回false,表示获取失败。在获取锁成功后,执行同步代码块;在finally块中释放锁,确保锁的释放。 

公平锁

定义

ReentrantLock提供了公平锁和非公平锁两种模式。

在公平锁模式下,线程按照它们发出请求的顺序来获取锁,即先到先得。公平锁保证了所有等待锁的线程能够公平地获得锁,避免了某些线程长时间无法获取锁的情况。但是,由于需要维护等待队列,因此公平锁的性能可能会略微降低。

示例

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

public class FairLockExample {
    private static final Lock fairLock = new ReentrantLock(true); // 创建一个公平锁

    public void someMethod() {
        fairLock.lock(); // 获取锁
        try {
            // 执行需要同步的代码块
        } finally {
            fairLock.unlock(); // 释放锁
        }
    }
}

条件变量

定义

条件变量(Condition)是Java多线程编程中的一种同步机制,它允许线程在等待某个条件成立时挂起自己,而不是忙等待。条件变量通常与锁结合使用,用于在等待某个共享资源的状态发生变化时唤醒等待的线程。

在Java中,条件变量通常与Lock对象的newCondition()方法结合使用,该方法返回一个与该Lock相关联的条件对象。通过条件对象的await()方法可以让线程等待条件的满足,而signal()或signalAll()方法可以唤醒等待的线程。

示例

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

public class ConditionVariableExample {
    private static final Lock lock = new ReentrantLock();
    private static final Condition condition = lock.newCondition();
    private static boolean conditionMet = false;

    public void awaitCondition() throws InterruptedException {
        lock.lock();
        try {
            while (!conditionMet) {
                condition.await(); // 等待条件满足
            }
            // 执行条件满足后的操作
        } finally {
            lock.unlock();
        }
    }

    public void signalCondition() {
        lock.lock();
        try {
            conditionMet = true; // 设置条件为满足状态
            condition.signal(); // 唤醒等待的线程
        } finally {
            lock.unlock();
        }
    }
}

在这个示例中,awaitCondition()方法等待条件的满足,如果条件不满足则调用condition.await()方法挂起线程。signalCondition()方法设置条件为满足状态,并调用condition.signal()方法唤醒等待的线程。条件变量通常用于多个线程之间的协作,可以有效地避免忙等待的情况。

  • 19
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值