死磕-java并发编程技术(二)

简介: 死磕-java并发编程技术(二)

一、线程通知与等待

1⃣️、wait()函数:Object类的方法

当一个线程调用一个共享变量的wait()方法时,该调用的线程会被阻塞挂起,直到发生下面的几个情况之一才返回:

a、其他线程调用了该共享变量的notify()或者notifyAll()方法;

b、其他线程调用了该线程的interrupt()方法,该线程抛出InterruptedExcepti on异常返回。

注意:如果调用wait方法的线程没有获取到该对象的锁的时候,则调用wait方法时调用线程会抛出IllegalMonitorStateException异常。

2⃣️、一个线程如何去获取到一个共享变量的锁呢?

a、执行synchronized同步代码块时,使用共享变量作为参数:

synchronized(共享变量) {

}

b、调用共享变量的方法,并且该方法使用了synchronized修饰

synchronized void  add(int a,int b) {

}

3⃣️、虚假唤醒

一个线程可以从挂起状态变成可以运行的状态,即使线程没有被其他线程调用notify(),notifyAll()方法进行通知,或者被中断,或者等待超时,这就是所谓的虚假唤醒,虽然在应用实践过程中很少发生,但是要防患于未然,做法就是不停的去探测该线程被唤醒的条件是否满足,不满足则会继续等待,代码如下:

synchronized (obj){
       while(条件不满足){       obj.wait();   }}

4⃣️、举一个更深刻的例子:

import java.util.concurrent.ArrayBlockingQueue;
//创建一个生产者的线程
public class Producer extends Thread {
    ArrayBlockingQueue<String> queue;
    public Producer (ArrayBlockingQueue<String> queue){
        this.queue=queue;
    }
    public void run() {
        synchronized (queue){
            //消费队列满,则等待队列空闲
            while(queue.size()==10){
                //挂起该线程,并释放通过同步块获取的queue上的锁,让消费者线程可以获取到锁,然后获取到队列里面的原先
                try {
                    queue.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            //空闲则生成元素,并通知消费者消费
            queue.add("1");
            queue.notifyAll();
        }
    }
}
mport java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingDeque;
public class Consumer extends  Thread {
    ArrayBlockingQueue<String> queue=new ArrayBlockingQueue<>(10);
    public Consumer( ArrayBlockingQueue<String>  queue){
       this.queue=queue;
    }
    @Override
    public void run() {
       synchronized (queue){
         while(queue.size()==0){
             //挂起当前线程,并释放通过同步块获取的queue上的锁,让生产者线程可以获取到该锁,将生
             //元素放入队列
             try {
                 queue.wait();
                 //消费元素,并通知唤醒生产者线程
                 queue.take();
                 queue.notifyAll();
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }
          }
        }
    }
}

解释上面的代码的流程:

a、假设生产者线程A首先通过synchronized获取到了queue上的锁,那么后续其他的生产元素的线程和消费者线程将会在获取该获取锁的地方被阻塞挂起。

b、这时如果线程A获取到锁之后发现当前的队列已经满之后会调用wait()方法阻塞自己,然后会释放获取的queue上的锁。如果不释放锁的话,这时就会产生死锁的状态。

注意:当前线程调用共享变量的wait()方法的时候只会释放当前共享变量上的锁,如果当前线程还持有其他共享变量的锁,则这些锁是不会被释放的。下回用代码演示。

相关文章
|
4天前
|
算法 Java
JAVA并发编程系列(8)CountDownLatch核心原理
面试中的编程题目“模拟拼团”,我们通过使用CountDownLatch来实现多线程条件下的拼团逻辑。此外,深入解析了CountDownLatch的核心原理及其内部实现机制,特别是`await()`方法的具体工作流程。通过详细分析源码与内部结构,帮助读者更好地理解并发编程的关键概念。
|
2天前
|
存储 Java
Java编程中的对象和类
【8月更文挑战第55天】在Java的世界中,“对象”与“类”是构建一切的基础。就像乐高积木一样,类定义了形状和结构,而对象则是根据这些设计拼装出来的具体作品。本篇文章将通过一个简单的例子,展示如何从零开始创建一个类,并利用它来制作我们的第一个Java对象。准备好让你的编程之旅起飞了吗?让我们一起来探索这个神奇的过程!
22 10
|
3天前
|
Java API 容器
JAVA并发编程系列(10)Condition条件队列-并发协作者
本文通过一线大厂面试真题,模拟消费者-生产者的场景,通过简洁的代码演示,帮助读者快速理解并复用。文章还详细解释了Condition与Object.wait()、notify()的区别,并探讨了Condition的核心原理及其实现机制。
|
3天前
|
Java
JAVA并发编程系列(9)CyclicBarrier循环屏障原理分析
本文介绍了拼多多面试中的模拟拼团问题,通过使用 `CyclicBarrier` 实现了多人拼团成功后提交订单并支付的功能。与之前的 `CountDownLatch` 方法不同,`CyclicBarrier` 能够确保所有线程到达屏障点后继续执行,并且屏障可重复使用。文章详细解析了 `CyclicBarrier` 的核心原理及使用方法,并通过代码示例展示了其工作流程。最后,文章还提供了 `CyclicBarrier` 的源码分析,帮助读者深入理解其实现机制。
|
3天前
|
设计模式 安全 Java
Java 编程中的设计模式:单例模式的深度解析
【9月更文挑战第22天】在Java的世界里,单例模式就像是一位老练的舞者,轻盈地穿梭在对象创建的舞台上。它确保了一个类仅有一个实例,并提供全局访问点。这不仅仅是代码优雅的体现,更是资源管理的高手。我们将一起探索单例模式的奥秘,从基础实现到高级应用,再到它与现代Java版本的舞蹈,让我们揭开单例模式的面纱,一探究竟。
22 11
|
3天前
|
缓存 负载均衡 Dubbo
Dubbo技术深度解析及其在Java中的实战应用
Dubbo是一款由阿里巴巴开源的高性能、轻量级的Java分布式服务框架,它致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案。
20 6
|
1天前
|
算法 安全 Java
JAVA并发编程系列(12)ThreadLocal就是这么简单|建议收藏
很多人都以为TreadLocal很难很深奥,尤其被问到ThreadLocal数据结构、以及如何发生的内存泄漏问题,候选人容易谈虎色变。 日常大家用这个的很少,甚至很多近10年资深研发人员,都没有用过ThreadLocal。本文由浅入深、并且才有通俗易懂方式全面分析ThreadLocal的应用场景、数据结构、内存泄漏问题。降低大家学习啃骨头的心理压力,希望可以帮助大家彻底掌握并应用这个核心技术到工作当中。
|
1天前
|
Java 程序员 编译器
死磕-高效的Java编程(二)
死磕-高效的Java编程(二)
|
1天前
|
存储 Java 调度
死磕-java并发编程技术(一)
死磕-java并发编程技术(一)
|
2天前
|
Java 调度 开发者
Java中的多线程编程:从基础到实践
本文旨在深入探讨Java多线程编程的核心概念和实际应用,通过浅显易懂的语言解释多线程的基本原理,并结合实例展示如何在Java中创建、控制和管理线程。我们将从简单的线程创建开始,逐步深入到线程同步、通信以及死锁问题的解决方案,最终通过具体的代码示例来加深理解。无论您是Java初学者还是希望提升多线程编程技能的开发者,本文都将为您提供有价值的见解和实用的技巧。
9 2