当前位置: 首页 > wzjs >正文

专业的移动网站建设小广告网页

专业的移动网站建设,小广告网页,北京市住房建设委官方网站,中小微企业名录查询1. Java并发包中的管程:Lock和Condition 1.1. Lock 的核心意义:再造管程 Java 原生的 synchronized 关键字已经是管程的一种实现,那为什么还要提供 Lock 接口? 原因是: Lock 弥补了 synchronized 的三大缺陷&#…

1. Java并发包中的管程:Lock和Condition

1.1. Lock 的核心意义:再造管程

Java 原生的 synchronized 关键字已经是管程的一种实现,那为什么还要提供 Lock 接口?

原因是:

Lock 弥补了 synchronized 的三大缺陷,尤其是在解决“死锁”中的不可抢占条件时具有更强的灵活性。

三种解决“不可抢占”的能力(也是 Lock 的优势):

1. 可中断获取锁

void lockInterruptibly() throws InterruptedException;
  • 遇到死锁时可通过中断来释放已有资源。

2. 支持超时的获取锁

boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
  • 限时等待,避免无限期阻塞。

3. 非阻塞地获取锁

boolean tryLock();
  • 获取不到立即返回,避免线程挂起。

1.2. Lock 的可见性保障原理

问题:

在使用 Lock 的并发场景中,如何确保对共享变量修改的可见性?

解决方案:

基于 Java 内存模型的 Happens-Before 原则ReentrantLock 内部的 volatile state 实现:

  • 解锁前后的顺序性保证(线程内)
  • volatile 变量规则(state 的读写)
  • 传递性规则:T1 修改变量 → 解锁 → T2 加锁 → 可见

1.3. 可重入锁(ReentrantLock)、公平锁与非公平锁

1. 可重入锁(ReentrantLock)

可重入锁的定义:指的是线程可以重复获取同一把锁。

示例:

例如下面代码中,当线程 T1 执行到 ① 处时,已经获取到了锁 rtl ,当在 ① 处调用 get() 方法时,会在 ② 再次对锁 rtl 执行加锁操作。此时,如果锁 rtl 是可重入的,那么线程 T1 可以再次加锁成功;如果锁 rtl 是不可重入的,那么线程 T1 此时会被阻塞。

class X {private final Lock rtl =new ReentrantLock();int value;public int get() {// 获取锁rtl.lock();         ②try {return value;} finally {// 保证锁能释放rtl.unlock();}}public void addOne() {// 获取锁rtl.lock();  try {value = 1 + get(); ①} finally {// 保证锁能释放rtl.unlock();}}
}
  • 可重入锁可避免同一个线程因为重复获取锁而造成死锁。

可重入函数(线程安全的):

重入函数,指的是多个线程可以同时调用该函数,每个线程都能得到正确结果;同时在一个线程内支持线程切换,无论被切换多少次,结果都是正确的。

2. 公平锁与非公平锁

区别:

  • 公平锁:先到先得,排队唤醒,避免线程“饿死”
  • 非公平锁(默认):允许插队,有更好的性能表现
// 无参构造函数:默认非公平锁
public ReentrantLock() {sync = new NonfairSync();
}
// 根据公平策略参数创建锁
public ReentrantLock(boolean fair){sync = fair ? new FairSync() : new NonfairSync();
}

1.4. 用锁的最佳实践

最佳实践(出自 Doug Lea):

  1. 只在更新对象的成员变量时加锁
  2. 只在访问可变成员变量时加锁
  3. 不要在加锁后调用其他对象的方法
    • 可能造成不可控延迟(例如 IO、sleep)
    • 可能加其他锁,引发死锁风险

补充建议:

  • 减少锁的持有时间(快速释放)
  • 降低锁的粒度(尽可能小范围加锁)
  • 避免锁的嵌套调用

总结:

  • Lock 提供了比 synchronized 更丰富和灵活的控制机制。
  • 使用 Lock 编写并发程序时,应牢记:
    • 能不能中断?
    • 能不能超时?
    • 能不能快速失败?
  • 最好的并发代码是简单、清晰、易于分析的。

1.5. Condition的概念

Lock 与 synchronized 的区别:

  • 支持中断响应(lock.lockInterruptibly()
  • 支持超时获取锁(tryLock(timeout)
  • 支持非阻塞获取锁(tryLock()

Condition 是什么?

  • 管程中的条件变量
  • Object.wait/notify 相比,Condition 支持多个条件变量,适用于更复杂的并发场景(如阻塞队列:notEmptynotFull)。

Condition 使用示例:阻塞队列

public class BlockedQueue<T> {final Lock lock = new ReentrantLock();final Condition notFull = lock.newCondition();   // 队列不满final Condition notEmpty = lock.newCondition();  // 队列不空void enq(T x) {lock.lock();try {while (队列已满) {notFull.await();}// 执行入队操作...notEmpty.signal();  // 通知可以出队} finally {lock.unlock();}}void deq() {lock.lock();try {while (队列为空) {notEmpty.await();}// 执行出队操作...notFull.signal();  // 通知可以入队} finally {lock.unlock();}}
}
  • 注意:Lock 和 Condition 实现的管程,线程等待和通知需要调用 await()、signal()、signalAll(),它们的语义和 wait()、notify()、notifyAll() 是相同的。

1.6. 异步与同步的本质

同步: 调用方必须等待结果返回(如函数调用阻塞当前线程)。

异步: 调用方无需等待结果,调用立即返回,后续结果通过回调或其他方式通知。

举例:

pai1M(); // 如果阻塞等结果 -> 同步
printf("hello world"); // 若立即执行,不等待上面 -> 异步

实现异步的两种方式:

  1. 调用方创建线程: 在子线程中调用(常见于主线程不被阻塞的情况)。
  2. 被调用方创建线程: 方法中主动异步处理逻辑,主线程立即 return。

1.7. 异步转同步

异步转同步:

调用本来是异步执行的,但我们人为“阻塞住”当前线程,等它的结果返回后再继续执行,从而模拟出同步调用的效果。

知识点

说明

异步调用

不等待结果,直接返回

同步调用

等待结果,阻塞线程

Dubbo 的异步转同步

发送请求是异步的,但通过 .get()进行线程等待

核心实现

Lock+ Condition,通过 await()阻塞、signal()唤醒

好处

兼顾性能(异步发送)和易用性(同步获取结果)

1.8. Lock-Condition例子

示例功能:

  • 有一个共享队列
  • 生产者线程往队列里放数据;
  • 消费者线程从队列中取数据;
  • 使用 ReentrantLockCondition 实现线程间的等待和唤醒机制

Java代码:

import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class LockConditionExample {// 定义一个固定大小的共享队列private static final int CAPACITY = 5;private final Queue<Integer> queue = new LinkedList<>();// 显式锁对象private final Lock lock = new ReentrantLock();// 队列满时:生产者等待的条件private final Condition notFull = lock.newCondition();// 队列空时:消费者等待的条件private final Condition notEmpty = lock.newCondition();// 生产者方法public void produce(int value) throws InterruptedException {lock.lock(); // 获取锁try {// 如果队列已满,则等待 notFull 条件while (queue.size() == CAPACITY) {System.out.println("队列满了,生产者等待...");notFull.await(); // 进入等待并释放锁}// 加入元素到队列queue.offer(value);System.out.println("生产者生产了: " + value);// 通知消费者:队列非空notEmpty.signal();} finally {lock.unlock(); // 释放锁}}// 消费者方法public int consume() throws InterruptedException {lock.lock(); // 获取锁try {// 如果队列为空,则等待 notEmpty 条件while (queue.isEmpty()) {System.out.println("队列空了,消费者等待...");notEmpty.await(); // 进入等待并释放锁}// 从队列中取出一个元素int value = queue.poll();System.out.println("消费者消费了: " + value);// 通知生产者:队列不满了notFull.signal();return value;} finally {lock.unlock(); // 释放锁}}// 主函数 - 启动生产者和消费者线程public static void main(String[] args) {LockConditionExample example = new LockConditionExample();// 生产者线程Thread producer = new Thread(() -> {int value = 0;try {while (true) {example.produce(value++);Thread.sleep(500); // 模拟生产速度}} catch (InterruptedException e) {Thread.currentThread().interrupt();}});// 消费者线程Thread consumer = new Thread(() -> {try {while (true) {example.consume();Thread.sleep(1000); // 模拟消费速度}} catch (InterruptedException e) {Thread.currentThread().interrupt();}});// 启动线程producer.start();consumer.start();}
}

疑问:

它们共享一个锁,但它们仍然能「协作式」地工作。不是并行执行临界区的代码,而是轮流进入、协同完成任务。

这意味着:
同一时刻只能有一个线程(无论是生产者还是消费者)进入加锁的代码块,也就是说:

  • 生产者线程进入produce() 方法时,消费者线程如果也想进入 consume() 方法,就必须等待
  • 同样,反过来也一样。

那为什么说它们“可以协同工作”?

因为它们用 Condition 做了同步等待与唤醒

具体情况如下:

场景

行为

队列满时

生产者执行 notFull.await()→ 放弃锁 → 等待消费者消费后唤醒它

队列有空位了

消费者 signal()唤醒了 notFull.await()处的生产者

队列空时

消费者执行 notEmpty.await() → 放弃锁 → 等待生产者生产后唤醒它

队列有数据了

生产者 signal()唤醒了notEmpty.await()处的消费者

  • 所以虽然它们使用同一个锁,但通过Condition 的等待和唤醒机制,实现了“互不干扰”的轮流工作流程 —— 类似于两个人轮流进一个房间传递东西,每次只能一个人进去,但彼此不会阻碍工作流程
http://www.dtcms.com/wzjs/93192.html

相关文章:

  • wordpress怎么改模板白帽优化关键词排名seo
  • 网站建设与网站设计哪个好学求个没封的网站2022
  • 陕西省政府网站建设上海sem
  • 郑州网站建设维护网站免费建站app
  • 网站做外链平台有哪些刚刚突发1惊天大事
  • 广告艺术设计专业介绍网站优化提升排名
  • 用web做购物网站百度宣传广告要多少钱
  • 怎么样再自己的网站做二级域名武汉大学人民医院官网
  • 宁波做网站的专业公司软文媒体发稿平台
  • 太原网站建设详细策划下载手机百度最新版
  • 企业网站站内优化搭建一个网站
  • 购物网站 后台模板手机百度seo快速排名
  • 网站建设哪家好知道产品软文范例500字
  • 中国佛山营销网站建设平台推广怎么做
  • 做网站和域名简述网站内容如何优化
  • 医院网站可以自己做吗百度搜索引擎推广
  • 网站备案如何申请网站竞价推广托管公司
  • 新网站如何做seo优化seo自媒体培训
  • 阿里云网站备份seo技术服务外包
  • 建设小型网站价钱最有效的15个营销方法
  • 成都网页设计美工培训南昌seo计费管理
  • 北京红酒网站建设长沙岳麓区
  • 地方网站 域名选择营销策划公司介绍
  • 企业网站的设计要点新闻摘抄2022最新20篇
  • 淘宝做关键词的网站广告最多的网站
  • 潍坊网站建设seo百度霸屏推广多少钱一个月
  • 做网站样品图片怎么拍照南宁seo结算
  • 深圳南园网站建设商业软文
  • 六安营销公司优化网站搜索
  • 兰州拼团网站建设郑州网站制作