03. 就该这么学并发 - 线程的阻塞

高并发下阻塞队列的选择 阅读详情

前言

上章介绍了**线程生命周期的就绪和运行**状态

这章讲下线程生命周期中最复杂的**阻塞**状态

阻塞(Blocked)

在开始之前

我们先**科普**几个概念

阻塞,挂起,睡眠 区分

阻塞
在线程执行时,所需要的资源不能立马得到,则线程被“阻塞”,直到满足条件则会继续执行

阻塞是一种“被动”的状态

挂起
线程执行时,因为“主观”需要,需要暂停执行当前的线程,此时需要“挂起”当前线程.

挂起是“主动”的动作行为,因为是“主动”的,所以“挂起”的线程需要“唤醒”才能继续执行

睡眠
线程执行时,因为“主观”需要,需要等待执行一段时间后再继续执行,
此时需要让当前线程睡眠一段时间

睡眠和挂起一样,也是“主动”的动作行为,不过和挂起不一样的是,它规定了时间!

我们举个形象的例子来说明

假设你是个主人,雇佣了一个佣人

挂起: 你主动对阿姨说 “你先去休息,有需要我再喊你”

睡眠: 你主动对阿姨说 “你去睡两个小时,然后继续干活”

阻塞: 阿姨自己没在干活,因为干活的工具不见了,等有了工具,她会自觉继续干活

明白了以上概念,我们继续了解,线程什么情况会阻塞?

线程阻塞原因

对于线程来讲,当发生如下情况时,线程将会进入阻塞状态:

  • 线程调用一个**阻塞式I/O方法**,在该方法返回之前,该线程被阻塞

  • 线程试图获得一个**同步监视器**,但该同步监视器正被其他线程所持有

  • 线程调用**sleep()**: sleep()不会释放对象锁资源,指定的时间一过,线程自动重新进入就绪状态

  • 线程调用**wait()**: wait()会释放持有的对象锁,需要notify( )或notifyAll()唤醒

  • 线程调用**suspend()挂起(已废弃,不推荐使用**): resume()(已废弃,不推荐使用)可以唤醒,使线程重新进入就绪状态

  • 线程调用**Join()**方法: 如线程A中调用了线程B的Join()方法,直到线程B线程执行完毕后,线程A才会被自动唤醒,进入就绪状态

需要说明的是

  • 在阻塞状态的线程**只能进入就绪状态,无法直接进入运行状态**

  • 就绪和运行状态之间的转换通常**不受程序控制,而是由系统线程调度**所决定

    • 当处于就绪状态的线程**获得**CPU时间片时,该线程进入运行状态;

    • 当处于运行状态的线程**失去**CPU时间片时,该线程进入就绪状态;

    • 但有一个方法例外**yield( ):
      使得线程
      放弃当前分得的CPU的时间片,
      但是
      不使线程阻塞,即线程仍然处于就绪状态**
      随时可能再次分得CPU的时间片进入执行状态
      调用yield()方法可以让**运行状态的线程转入就绪状态**

  • **sleep()/suspend()/rusume()/yield()**均为Thread类的方法,
    **wait()/notify()/notifyAll()**为Object类的方法

对象锁 和 监视器

细心的朋友可能注意到以上提到了个名词“监视器”,和“对象锁”,他们是个啥?

在JVM的规范中,有这么一些话:

“在JVM中,每个对象和类在逻辑上都是和一个监视器相关联的”  

“为了实现监视器的排他性监视能力,JVM为每一个对象和类都关联一个锁”   

“锁住了一个对象,就是获得对象相关联的监视器”   

引用一个流传很广的例子来解释

可以将监视器比作一个建筑,
它有一个很特别的房间,
房间里有一些数据,而且在同一时间只能被一个线程占据,
一个线程从进入这个房间到它离开前,它可以独占地访问房间中的全部数据.

进入这个建筑叫做"进入监视器"
进入建筑中的那个特别的房间叫做"获得监视器"
占据房间叫做"持有监视器"
离开房间叫做"释放监视器"
离开建筑叫做"退出监视器"

而一个锁就像一种任何时候只允许一个线程拥有的特权,
一个线程可以允许多次对同一对象上锁,
对于每一个对象来说,java虚拟机维护一个计数器,记录对象被加了多少次锁,
没被锁的对象的计数器是0, 
线程每加锁一次,计数器就加1,
每释放一次,计数器就减1,
当计数器跳到0的时候,锁就被完全释放了

Java中使用同步监视器的代码很简单,使用关键字 “synchronized”即可

synchronized (obj){            
    //需要同步的代码
    //obj是同步监视器
}
public synchronized void foo(){
    //需同步的代码        
    //当前对象this是同步监视器
}

关于**synchronized**的详细使用有很多注意点, 我们后续单独开一章来讲解.

阻塞状态分类

阻塞分类.png

根据阻塞产生的原因不同,阻塞状态又可以分为三种:

  • 等待阻塞
运行中的线程执行wait()方法,该线程会释放占用的所有资源对象,
JVM会把该线程放入该对象的“等待队列”中,进入这个状态后,是不能自动唤醒的,
必须依靠其他线程调用notify()或notifyAll()方法才能被唤醒,
唤醒后进入“阻塞(同步队列)”
  • 同步阻塞
就绪状态的线程,被分配了CPU时间片,
准备执行时发现需要的资源对象被synchroniza(同步)(资源对象被其它线程锁住占用了),
获取不到锁标记,该线程将会立即进入锁池状态,等待获取锁标记,
这时的锁池里,也许已经有了其他线程在等待获取锁标记,
这时它们处于队列状态,既先到先得
一旦线程获得锁标记后,就转入就绪状态,继续等待CPU时间片
  • 其他阻塞
运行的线程调用了自身的sleep()方法或其他线程的join()方法,
或者发出了I/O请求时,JVM会把该线程置为阻塞状态.
当sleep()状态超时、join()等待线程终止或者超时、
或者I/O处理完毕时,线程重新转入就绪状态,等待CPU分配时间片执行

Thread类相关方法介绍

看完以上阻塞的介绍,可能很多朋友对Thread类的一些方法产生了疑问,下面我们来实际探究下这些方法的使用,相关的注意点我就直接写在注释中方便阅读

public class Thread{
    // 线程的启动
    public void start(); 
    // 线程体,线程需要做的事
    public void run(); 
    // 已废弃,停止线程
    public void stop(); 
    // 已废弃,挂起线程,(不释放对象锁)
    public void suspend(); 
    // 已废弃,唤醒挂起的线程
    public void resume(); 
    // 在指定的毫秒数内让当前正在执行的线程休眠(不释放对象锁)
    public static void sleep(long millis); 
    // 同上,增加了纳秒参数(不释放对象锁)
    public static void sleep(long millis,int nanos); 
    //线程让步(不释放对象锁)
    public static void yield();
    // 测试线程是否处于活动状态
    public boolean isAlive(); 
    // 中断线程
    public void interrupt(); 
    // 测试线程是否已经中断
    public boolean isInterrupted(); 
    // 测试当前线程是否已经中断
    public static boolean interrupted(); 
    // 等待该线程终止
    public void join() throws InterruptedException; 
    // 等待该线程终止的时间最长为 millis 毫秒
    public void join(long millis) throws InterruptedException; 
    // 等待该线程终止的时间最长为 millis 毫秒 + nanos 纳秒
    public void join(long millis,int nanos) throws InterruptedException; 
}

我们可以看出,Thread类很多方法因为线程安全问题已经被弃用了,比如我们讲的**suspend()/resume(), 因为它会产生死锁**

现在

挂起是JVM的系统行为,我们无需干涉

suspend()/resume()产生死锁的原因

当**suspend()的线程持有某个对象锁,而resume()**它的线程又正好需要使用此锁的时候,死锁就产生了

举个例子:

有两个线程A和B,以及一个公共资源O

A执行时需要O对象,所以A拿到了O锁住,防止操作时O再被别的线程拿走,之后suspend挂起,

B呢,负责在适当的时候resume唤醒A,但是B执行时也需要拿到O对象

此时,死锁产生了

A拿着O挂起,因为resume的实现机制,所以挂起时O不会被释放,

只有A被resume唤醒继续执行完毕才能释放O,

B本来负责唤醒A,但是B又拿不到O,

所以,A和B永远都在等待,执行不了

说到Thread类的**suspend和/resume,顺带也提下Object类的wait/notify这对组合,wait/notify**属于对象方法,意味着所有对象都会有这两个方法.

wait/notify

这两个方法同样是等待/通知,但使用它们的**前提是已经获得了锁,且在wait(等待)期间会释放锁**

线程要调用wait(),必须先获得该对象的锁,在调用wait()之后,当前线程**释放该对象锁并进入休眠**,只有以下几种情况下会被唤醒

- 其他线程调用了该对象的notify()(随机唤醒等待队列的一个线程)
或notifyAll()(随机等待队列的所有线程); 

- 当前线程被中断; 

- 调用wait(3000)时指定的时间(3s)已到.
类方法和对象方法区别( sleep() & wait() )

这里重点再强调下类方法和对象方法的区别,我们以**sleep和wait**为例

sleep方法是Thread类静态方法,直接使用Thread.sleep()就可以调用

最好不要用Thread的实例对象调用它,因为它睡眠的始终是当前正在运行的线程

它只对正在运行状态的线程对象有效

使用sleep方法时,一定要用try catch处理InterruptedException异常

我们举个例子

//定义一个线程类
public class ImpRunnableThread implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 3; i++) {
            System.out.println("线程: " +  Thread.currentThread().getName() + "第" + i + "次执行!");
        }
    }
}

//测试
class Test {
    public void main(String[] args){
    Thread t = new Thread(new ImpRunnableThread());
     t.start();
     //很多人会以为睡眠的是t线程,但其实是main线程
     t.sleep(5000);
     for (int i = 0; i < 3; i++) {
          System.out.println("线程: " +    Thread.currentThread().getName() + "第" + i + "次执行!");
    }
}

先不说直接 “对象.sleep()” 这种使用方式本就不对,

再者 **t.sleep(5000)**很多人会以为是让t线程睡眠5s,

但其实睡眠的是main线程!

我们执行代码,就可以看出,t线程会先执行完毕,5s后主线程才会输出!

那么问题来了,如何让t线程睡眠呢??

很简单,我们在ImpRunnableThread类的run()方法中写sleep()即可!

public class ImpRunnableThread implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 3; i++) {
            //sleep()一定要try catch
            try {
                if (i == 2) {
                    //t线程睡眠5s
                    Thread.sleep(5000);
                }
                System.out.println("线程: " + Thread.currentThread().getName() + "第" + i + "次执行!");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }}}
}

说完类方法,我们再说对象方法

对象锁: 即针对一个“实例对象”的锁,java中,所有的对象都可以“锁住”,这里举个简单的例子

//实例一个Object对象
Object lock = new Object();
//使用synchronized将lock对象锁住
synchronized(lock){
    //锁保护的代码块
}

在Object对象中有三个方法**wait()、notify()、notifyAll()**

  • wait()
wait()方法可以使调用该方法的线程释放共享资源的锁,
然后从运行状态退出,进入阻塞(等待队列),直到再次被唤醒(进入阻塞(同步队列)).

这里需要注意,形如wait(3000)这样的带参构造,
无需其它线程notify()或notifyAll()唤醒,到了时间会自动唤醒,
看似和sleep(3000)一样,但其实是不同的
wait(3000)调用时会释放对象锁,3s过后,进入阻塞(同步队列),
竞争到对象锁后进入就绪状态,而后cpu调度执行.
所以,实际等待时间比3s会长!!

而sleep(3000),不会释放对象锁,
3s过后,直接进入就绪状态,等待cpu调度执行.
  • notify()
notify()方法可以随机唤醒阻塞(等待队列)中等待同一共享资源的一个线
程,并使得该线程退出等待状态,进入阻塞(同步队列)
  • notifyAll()
notifyAll()和notify()类似,不过它唤醒了阻塞(等待队列)中等待
同一共享资源的所有线程

最后,如果**wait()方法和notify()/notifyAll()方法不在同步方法/同步代码块中**被调用,那么虚拟机会抛出

java.lang.IllegalMonitorStateException

接下来我们来看看具体任何使用

定义一个等待线程WaitThread

class WaitThread extends Thread {
    private Object lock;

    public WaitThread(Object lock) {
        this.lock = lock;
    }

    @Override
    public void run() {
        try {
            synchronized (lock) {
                System.out.println(
                        "start---" + Thread.currentThread().getName() + "---wait time = " + System.currentTimeMillis());
                lock.wait();
                System.out.println(
                        "end---" + Thread.currentThread().getName() + "---wait time = " + System.currentTimeMillis());
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

定义一个唤醒线程NotifyThread

class NotifyThread extends Thread {
    private Object lock;

    public NotifyThread(Object lock) {
        this.lock = lock;
    }

    @Override
    public void run() {
        synchronized (lock) {
            System.out.println(
                    "start---" + Thread.currentThread().getName() + "---wait time = " + System.currentTimeMillis());
            lock.notify();
            System.out.println(
                    "end---" + Thread.currentThread().getName() + "---wait time = " + System.currentTimeMillis());
        }
    }
}

测试代码

public class Test {
    public static void main(String[] args) throws Exception {
        Object lock = new Object();
        WaitThread w1 = new WaitThread(lock);
        w1.setName("等待线程");
        w1.start(); 
        //main线程睡眠3s,便于我们看到效果
        Thread.sleep(3000);
        NotifyThread n1 = new NotifyThread(lock);
        n1.setName("唤醒线程");
        n1.start();
    }
}

结果

start---等待线程---wait time = 1589425525994
start---唤醒线程---wait time = 1589425529001
end---唤醒线程---wait time = 1589425529001
end---等待线程---wait time = 1589425529001

结果可以看出,等待线程被唤醒线程唤醒后才继续输出.
需要注意的是,如果等待线程设置的是**wait(3000),则无需唤醒线程唤醒,它自己在3s**后会继续执行.

等待队列 & 同步队

前面一直提到两个概念,等待队列(等待池),同步队列(锁池),这两者是不一样的.具体如下:

同步队列(锁池)

假设线程A已经拥有了某个对象(注意:不是类)的锁,
而其它的线程想要调用这个对象的某个synchronized方法(或者synchronized块),
由于这些线程在进入对象的synchronized方法之前必须先获得该对象的锁的拥有权,
但是该对象的锁目前正被线程A拥有,
所以这些线程就进入了该对象的同步队列(锁池)中,
这些线程状态为Blocked.

等待队列(等待池)

假设一个线程A调用了某个对象的wait()方法,
线程A就会释放该对象的锁
(因为wait()方法必须出现在synchronized中,
这样自然在执行wait()方法之前线程A就已经拥有了该对象的锁),
同时 线程A就进入到了该对象的等待队列(等待池)中,
此时线程A状态为Waiting.
如果另外的一个线程调用了相同对象的notifyAll()方法,
那么处于该对象的等待池中的线程
就会全部进入该对象的同步队列(锁池)中,准备争夺锁的拥有权.
如果另外的一个线程调用了相同对象的notify()方法,
那么仅仅有一个处于该对象的等待池中的线程(随机)会进入该对象的同步队列(锁池)

被**notify()或notifyAll()唤起的线程是有规律**的

- 如果是通过notify来唤起的线程,那 先进入wait的线程会先被唤起来;

- 如果是通过nootifyAll唤起的线程,默认情况是 最后进入的会先被唤起来,即LIFO的策略;

请关注我的订阅号

订阅号.png

电容式触摸抗干扰设计:工业环境下的实践方案 针对工业环境中电容式touch器件易受干扰的问题,分享实用的硬件布局与软件滤波方案,提升touch响应稳定性和可靠性。 阅读详情

相关推荐

PHP实战:5分钟搞定SM4国密加密算法集成(附完整代码)

本文详细介绍了如何在PHP项目中快速集成SM4国密加密算法,提供完整的代码实现和实际应用示例。从算法原理到核心代码解析,再到性能优化与安全实践,帮助开发者高效实现数据加密功能,满足金融、政务等领域的合规需求。

weixin_29315569的博客 353

java 线程池 阻塞超时_java – 修复线程池线程阻塞,当提交足够的任务时

我有一个需要并行计算许多小任务的过程,然后按照任务的自然顺序处理结果.为此,我有以下设置:一个简单的ExecutorService和一个阻塞队列,我将使用它来保持在将Callable提交给执行程序时返回的Future对象:ExecutorService exec = Executors.newFixedThreadPool(15);LinkedBlockingQueue> futures =...

weixin_32103331的博客 1078

Transformer在CV里太耗算力?手把手拆解Restormer的MDTA与GDFN模块

本文深度解析了CVPR2022最佳论文提名作品Restormer的创新模块MDTA与GDFN,有效解决了Transformer在计算机视觉领域的高计算复杂度问题。通过通道注意力降维和门控前馈网络设计,Restormer在图像恢复重建任务中显著降低计算量,同时保持高性能,为实时图像处理提供了可行方案。

weixin_30258901的博客 444

线程阻塞队列的处理

   在日常事务中,我们常常依次做如下操作:  排队取得一个单号; 根据这个单号享有一个操作; 为当前的这个操作买单. 在Android中也一样,为了不阻塞主线程,我们把所有耗时行为都封装为多个线程,有的时候需要先运行线程A,根据得到的结果再运行线程B, 再根据B的结果运行线程C. 时序图如下:  如果我们在ThreadA结束前的代码中插入ThreadB.start, 再ThreadB的结束前...

UC工作室[QQ:5805661 主页: http://www.app4u.com.cn] 132

昆仑通态屏幕制作(连载1)---接触篇

写在开始 背景:最近出了做QT、LORA和4G,还做了一个屏幕。以前做了一个迪文的串口屏幕,发现网上的教程很多,所以连载就不更新了,并且迪文屏幕的设置什么的比较简单,应该从网上都能找到对应的教程。而现在用的昆仑通态的屏幕属于嵌入式屏幕,至于为啥叫嵌入式,也不是很明白,反正就是需要用这个屏幕,嵌入式不嵌入式不重要了。重要的是能用,并且能实现串口屏幕不能实现的功能。所以选定昆仑通态的一款屏幕。 文章语言:我比较习惯用比较糙的语言介绍做的东西,有时候不太准备,但是为了方便理解,还请大家谅解。用...

weixin_45426095的博客 6734

VTK基础教程(1)- vtkPolyData 介绍

目录 VTK的编译与环境搭建 VTK一般渲染流程 VTK数据类型-vtkPolyData 使用vtk自带的多边形数据 使用自己创建的数据 添加顶点颜色 添加面颜色 VTK的编译与环境搭建 这部分目前已经有了大佬做了成熟的傻瓜式配置,大家可以参考这篇文章:VTK+VS2019(或其他版本均可) 傻瓜式一站式 配置_Nancy_fairy的博客-优快云博客_vs2019 vtk VTK一般渲染流程 这部分的介绍也很多,大家可以参考这篇文章:VTK笔记-了解VTK_黑山老妖的博客.

qq_35769071的博客 9052

并发举措七之阻塞队列

前言: 阻塞队列的典型使用场景就是生产者/消费者模式。本文会介绍Java7种阻塞队列。 一、阻塞对列的实现机制 阻塞队列,关键字是阻塞,先理解阻塞的含义,在阻塞队列中,线程阻塞有这样的两种情况: 1.当队列中没有数据的情况下,消费者端的所有线程都会被自动阻塞(挂起),直到有数据放入队列。 2.当队列中填满数据的情况下,生产者端的所有线程都会被自动阻塞(挂起),直到队列中有空的位置,线程被自动唤醒。 二、阻塞对列常用api 阻塞队列提供了四种处理...

heijunwei的博客 350

YOLOv8【第十章:多任务扩展深度篇·第18节】不规则工业缺陷分割——针对划痕、裂纹的 Seg 模型调优!

🏆 本文收录于 《YOLOv8实战:从入门到深度优化》 专栏。该专栏系统复现并梳理全网各类 YOLOv8 改进与实战案例(当前已覆盖分类 / 检测 / 分割 / 追踪 / 关键点 / OBB 检测等方向),坚持持续更新 + 深度解析,质量分长期稳定在 97 分以上,可视为当前市面上 覆盖较全、更新较快、实战导向极强 的 YOLO 改进系列内容之一。

**My Coding Family** 3978

java并发编程--get超时处理以及cancle方法的使用

#注意代码上面的注释 import java.util.concurrent.*; /** * @创建人 xiaoshi * @创建时间 2020/4/11 * @描述 练习get超时,以及cancle方法的使用。可知,在future调用处,捕捉超时异常后,可使用cancle方法 * 来对线程进行管理,将其关闭,传入的参数为:是否跑完线程,如果传入为false,那么线程将直接...

简单点,编程的方式简单点 643

ArcGIS笔记13_利用ArcGIS制作岸线与水深地形数据?建立水动力模型之前的数据收集与处理?

在利用MIKE建立水动力模型之前,需要收集、处理和制作诸多数据和资料,主要有岸线数据、水深地形数据、开边界潮位驱动数据、风场数据、潮位和海流观测资料和站点潮汐调和常数资料等。本篇主要介绍这些资料的获取与处理。

晏长街的博客 5948

gseapy python包GO、KEGG富集(注释)分析

文档案例参考:https://gseapy.readthedocs.io/en/latest/gseapy_example.html#Over-representation-analysis-by-Enrichr-web-services安装:建议安装最新版(这里安装的1.04):https://github.com/zqfang/GSEApy/releases。

weixin_42357472的博客 3610

线程阻塞原因分析介绍

导致线程阻塞的原因主要有以下几方面。 1、线程进行了休眠:线程执行了Thread.sleep(int n)方法,线程放弃CPU,睡眠n毫秒,然后恢复运行。 2、线程等待获取同步锁才能进行下一步操作:线程要执行一段同步代码,由于无法获得相关的同步锁,只好进入阻塞状态,等到获得了同步锁,才能恢复运行。 3、线程执行wait()进入阻塞状态:线程执行了一个对象的wait()方法,进入阻塞状态,只有等到其他线程执行了该对象的notify()或notifyAll()方法,才可能将其唤醒。 4、等待相关资源:线程执行I

路过的熊的博客 8541

[系统安全] 一.什么是逆向分析、逆向分析基础及经典扫雷游戏逆向

娜璋AI安全之家于2020年8月18日开通,将专注于Python和安全技术,主要分享Web渗透、系统安全、CVE复现、威胁情报分析、人工智能、大数据分析、恶意代码检测等文章。真心想把自己近十年的所学所做所感分享出来,与大家一起进步。 系统安全系列作者将深入研究恶意样本分析、逆向分析、攻防实战等,通过在线笔记和实践操作的形式分享与博友们学习,希望能与您一起进步。第一篇文章先带领大家学习什么是逆向分析,然后详细讲解逆向分析的典型应用,接着通过OllyDbg工具逆向分析经典的游戏扫雷,再通过Cheat Engin

杨秀璋的专栏 2万+

ServerSocket详解及线程阻塞_03

ServerSocket详解构造方法ServerSocket()ServerSocket(int port)ServerSocket(int port ,int backlog)serverSocket(int port,int backlog,InetAddress bindADDR)port是服务器绑定的端口(服务器要监听的端口);backlog是指定客户连接请求队列的长度(若设置为...

weixin_30439031的博客 582

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

Java线程池中的阻塞队列类型

在Java线程池中,阻塞队列是存储待执行任务的核心组件。以下是三种常用的阻塞队列类型,它们各自具有独特的特点和适用场景。

✨ 欢迎来到【Seal ^_^ 的优快云博客】!✨ 4767

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

Java线程状态、线程停止、线程阻塞

Java线程状态、线程停止、线程阻塞

吃果冻不吐果冻皮 5657

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

Java 中的阻塞 IO 和非阻塞 IO

IO(输入输出)操作是一个基础而又关键的部分。在 Java 中,处理 IO 通常涉及到阻塞 IO 和非阻塞 IO 两种模式。本文将介绍这两种模式的概念、特点以及在 Java 编程中的应用场景与区别。

✨ 欢迎来到【Seal ^_^ 的优快云博客】!✨ 5870

【重难点】【JUC 03】怎么实现一个线程安全的队列、手写模拟实现一个阻塞队列

怎么实现一个线程安全的队列、手写模拟实现一个阻塞队列

2022年毕业的萌新程序猿,输出一下自己的学习内容~ 1190

【线程探秘】Java并发艺术

科大讯飞高级架构师十余年经验总结!自顶向下详解Java线程实现原理与实践《一本书讲透Java线程:原理与实践》推文赠书

优快云站内信: https://i.youkuaiyun.com/#/msg/chat/qyj19920704 2万+

主线程 唤醒_Java并发编程:多线程如何实现阻塞与唤醒

线程的阻塞和唤醒在多线程并发过程中是一个关键点,当线程数量达到很大的数量级时,并发可能带来很多隐蔽的问题。如何正确暂停一个线程,暂停后又如何在一个要求的时间点恢复,这些都需要仔细考虑的细节。Java为我们提供了多种API来对线程进行阻塞和唤醒操作,比如suspend与resume、sleep、wait与notify以及park与unpark等等。01睡眠控制线程阻塞与唤醒的最简单方式就...

weixin_39827304的博客 166

03_并发高频

ReentrantLock 的底层实现主要依赖于 AQS 这个抽象类。AQS 是一个提供了基本同步机制的框架,其中包括了队列、状态值等。ReentrantLock 在AQS的基础上通过内部类Sync来实现具体的锁操作。可中断性:ReentrantLock实现了可中断性,这意味着线程在等待锁的过程中,可以被其他线程中断而提前结束等待。在底层,ReentrantLock 使用了与LockSupport.park()和LockSupport.unpark()相关的机制来实现可中断性。设置超时时间。

weixin_42658491的博客 2120

java多线程与线程池-03线程池与阻塞队列

队列是一种特殊的集合,一般队列都具有先进先出(FIFO)的特性(并不绝对要求)。优先级队列(PriorityQueue)按照元素的比较方法排序,其他队列基本采用自然序排队。队列Queue接口实现了Collection接口,offer()方法负责把元素插入队列中。peek()方法检索队列头是否存在元素(不移除元素),poll()方法则是检索并移除元素。当队列为空时,peek()和poll()方法都返回null。BlockingQueue为阻塞队列接口,它继承了Queue接口。BlockingQueue接口中新

天空鸟的博客 1270

绝了,66道并发多线程面试题汇总

线程是操作系统能够进⾏运算调度的最⼩单位,它被包含在进程之中,是进程中的实际运作单位,可以使⽤多线程对进⾏运算提速。线程安全:就是多线程访问时,采⽤了加锁机制,当⼀个线程访问该类的某个数据时,进⾏保护,其他线程不能进⾏访问,直到该线程读取完,其他线程才可使⽤。不会出现数据不⼀致或者数据污染。Vector 是⽤同步⽅法来实现线程安全的, ⽽和它相似的ArrayList不是线程安全的。

程序员高级码农的博客 1945

详细介绍:多线程高并发

高并发与多线程的关系与区别 liuhuiteng 2019-03-09 21:30:41 13357 收藏 80 分类专栏: Java进阶 文章标签: 高并发 多线程 高并发指标 高并发解决方案 一、什么是高并发 高并发(High Concurrency)是一种系统运行过程中遇到的一种“短时间内遇到大量操作请求”的情况,主要发生在web系统集中大量访问收到大量请求(例如:12306的抢票情况;天猫双十一活动)。该情况的发生会导致系统在这段时间内执行大量操作,例如对资源的请求、数据库的操作等。 二、高并发

weixin_47043353的博客 3919

多线程(五) ~ 阻塞队列与线程池

什么是阻塞队列?答: 阻塞队列是⼀种特殊的优先级队列. 也遵守 “先进先出” 的原则, 阻塞队列也有两个特性,当队列满的时候, 继续⼊队列就会阻塞, 直到有其他线程从队列中取走元素当队列空的时候, 继续出队列也会阻塞, 直到有其他线程往队列中插入元素为什么要用阻塞队列?答: 当客户端与服务器直接交互时, 如果遇到用户请求高峰期, 大量的请求会直接涌入服务器, 直接处理大量请求数据可能会把服务器搞挂掉, 那么这时就需要一个缓冲器来缓解这种特殊情况阻塞队列是可以循环使用的且不能扩容的, 我们把它设计成。

景画的博客 835

java线程阻塞 notify_Java并发编程:如何防止在线程阻塞与唤醒时死锁

Java并发编程:多线程如何实现阻塞与唤醒说到suspend与resume组合有死锁倾向,一不小心将导致很多问题,甚至导致整个系统崩溃。接着看另外一种解决方案,我们可以使用以对象为目标的阻塞,即利用Object类的wait()和notify()方法实现线程阻塞。当线程到达监控对象时,通过wait方法会使线程进入到等待队列中。而当其它线程调用notify时则可以使线程重新回到执行队列中,得以继续执行...

weixin_39942492的博客 137
上一篇: 40. 从零开始学springboot-再谈参数合法性验证
下一篇: 04. 就该这么学并发 - 线程的结束
码哥说
博客等级 码龄8年 5645粉丝 172原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

打赏作者

码哥说

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

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

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

打赏作者

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

抵扣说明:

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

余额充值