多线程高级

C# 多线程编程全面指南:从基础到高级实践 在现代软件开发中,多线程编程已成为提升应用程序性能的关键技术。C# 作为.NET平台的主力语言,提供了丰富的多线程处理机制。本文将全面介绍C#中的多线程编程技术,从基础概念到高级应用,帮助开发者掌握这一重要技能。 阅读详情

线程池

线程的状态

NEW
	至今尚未启动的线程处于这种状态。 
RUNNABLE
	正在 Java 虚拟机中执行的线程处于这种状态。 
BLOCKED
	受阻塞并等待某个监视器锁的线程处于这种状态。 
WAITING
	无限期地等待另一个线程来执行某一特定操作的线程处于这种状态。 
TIMED_WAITING
	等待另一个线程来执行取决于指定等待时间的操作的线程处于这种状态。 
TERMINATED
	已退出的线程处于这种状态。 

我们自己频繁的去创建和销毁线程比较消耗系统资源,同时也比较浪费时间。所以Java语言的API给我们提供了线程池的技术,帮我们解决这个问题。

当创建一个线程池,其实就是创建了一个能够存储线程的容器,需要执行线程任务是,就从线程池中拿一个线程出来用,用完之后再还给线程池。

创建默认的线程池

API提供了一个工具类叫Executors,可以用它的方法生成不同特点的线程池。

public static  ExecutorService newCachedThreadPool() 
    创建一个可以根据需要创建新线程的线程池。最多可以创建int最大值的线程数量
public static ExecutorService newFixedThreadPool(int nThreads)  
    创建一个固定长度的线程池
public static ExecutorService newSingleThreadExecutor() 
 	创建单个线程的线程池
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) 
     创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行。

以newCachedThreadPool方法为例,演示向线程池提交任务

//创建默认线程池:
ExecutorService executorService = Executors.newCachedThreadPool();

//提交线程任务
executorService.submit(new Runnable() {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"执行了");
    }
});

//提交线程任务
executorService.submit(new Runnable() {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"执行了");
    }
});
//关闭线程池
executorService.shutdown();

按周期执行某一个线程任务

ScheduledExecutorService 
     executorService = Executors.newScheduledThreadPool(3);
        //按照周期性执行某一个任务
        executorService.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"执行了");
            }
        },3,5, TimeUnit.SECONDS);

ThreadPoolExecutor创建线程池

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler)
参数解释:
    corePoolSize - 核心线程数。
    maximumPoolSize - 最大线程数。
    keepAliveTime - 临时线程存活的时间。
    unit - keepAliveTime 时间单位。
    workQueue - 阻塞队列。
    threadFactory -  创建线程的工厂。
    handler -  如果超过最大线程数,的拒绝方案。 

创建线程池的演示

ThreadPoolExecutor poolExecutor=new ThreadPoolExecutor(
    6, //核心线程数
    9, //最大线程数
    3, //空闲时间
    TimeUnit.SECONDS, //时间单位:秒
    new ArrayBlockingQueue<>(10),
    Executors.defaultThreadFactory(), //默认的工厂对象,由工厂对象帮我们生产线程
    new ThreadPoolExecutor.AbortPolicy() //拒绝的方式
); 

//提交任务
poolExecutor.submit(new Runnable() {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"执行了");
    }
}); 

拒绝策略

当提交的线程任务超过了最大线程数 + 阻塞队列长度,就会触发拒绝策略。

static class ThreadPoolExecutor.AbortPolicy 
          用于被拒绝任务的处理程序,它将抛出 RejectedExecutionException. 
static class ThreadPoolExecutor.CallerRunsPolicy 
          用于被拒绝任务的处理程序,它直接在 execute 方法的调用线程中运行被拒绝的任务;如果执行程序已关闭,则会丢弃该任务。 (让main线程执行多余的任务)
static class ThreadPoolExecutor.DiscardOldestPolicy 
          用于被拒绝任务的处理程序,它放弃最旧的未处理请求,然后重试 execute;如果执行程序已关闭,则会丢弃该任务。 
static class ThreadPoolExecutor.DiscardPolicy 
          用于被拒绝任务的处理程序,默认情况下它将丢弃被拒绝的任务

线程安全细节

volatile 关键字

当多个线程在访问共享数据时,不是直接访问的主内存的数据,而是在线程本地内存创建了一个和主内存一样的变量副本,对副本进行赋值,然后在重新赋值给主内存。

可能会出现多个线程临时存储的变量副本的值不一样,使用volatile修饰这个变量,就可以解决问题,强制让线程每次使用变量时,都从主内存中获取最新的值。

原子性

原子性指意思是多个操作是不可分割的原子项,他们要么同时成功,要么同时失败。 例如:当多线程在执行自增操作时,就不是原子性的。【本地内存】

自增操作,count++为例,其实底层是要完成三个步骤(这三个步骤是不可分割的)
    1.从主内存拷贝一个变量副本到线程本地内存
    2.对变量副本进行操作
    3.把变量副本的值写回主内存

但是由于CPU的随机性,可能一个线程没有完成这个三个步骤,执行权被其他线程抢走了,就破坏了原子性。

AtomicInteger类

直接使用int或者Integer对变量进行自增、修改、获取等操作,不能保证原子性,可能会出现线程安全的问题。

可使用synchronized来保证线程的安全性。这种方式解决问题的方式,是从悲观的角度出发,叫做悲观锁。

解决原子性的问题,Java提供了一系列的原子类。如AtomicInteger类就是其中的一个,它也表示整数,提供了一些方法可以对变量进行自增、获取、修改等操作,但是这些方法可以保证原子性,也能保证线程安全。

public int incrementAndGet()  
    对AtomicInteger包装的整数,先自增再获取。  //等价于 int num=10;  int c = ++num;

public int getAndincrement()
    对AtomicInteger包装的整数,先获取再自增。  //等价于 int num=10;  int c= num++;

public int getAndAdd(int delta)  
    对AtomicInteger包装的整数,先获取再增加。  //等价于 int num=10;
    									  //       int temp=num; //先获取num的值
    									  //       num+=5; //再对num值增加5
public int addAndGet(int delta)  
     对AtomicInteger包装的整数,先增加再获取	  //等价于 int num=10; 
    									   //      num+=5; /对num增加5
    									   //      int temp=num; //赋值后的值
public int getAndSet(int newValue)  
      对AtomicInteger包装的整数,先获取再设置

代码演示

//创建原子性的整数10
AtomicInteger ai = new AtomicInteger(10);

//先获取原来的值,再增加5
int result = ai.getAndAdd(5);
System.out.println("原来的值:" + result);//10
System.out.println("增加后的值:" + ai);//15

//先获取原来的值,再设置新的值
result = ai.getAndSet(20);
System.out.println("原来的值:" + result); //15
System.out.println("新的值:" + ai); //20

AtomicInteger类保证原子性的原理如下图所示

常见的线程安全的类

ArrayList和Vector
	ArrayList: 数组结构,线程不安全(效率高)
	Vector: 数组结构,线程安全的(效率低)

HashMap和Hashtable 
	HashMap: 哈希表结构(数组+链表),线程不安全的(效率高)
	Hashtable: 哈希表结构(数组+链表),线程安全的(同步代码块,效率低)
	ConcurrentHashMap: 哈希表结构(数组+链表+红黑树),线程安全的(同步代码块+CAS算法,效率高) 
   
StringBuilder和StringBuffer
	StringBuilder: 线程不安全的(效率高)
	StringBuffer: 线程安全的(效率低) 

CountDownLatch类

使用场景:当需要某一个线程在其他线程执行完毕之后才执行。

//第一个孩子
public class MyChildThread1 extends Thread {
    private CountDownLatch cdl;
    //利用构造方法,来给cdl赋值
    public MyChildThread1(CountDownLatch cdl) {
        this.cdl = cdl;
    }

    @Override
    public void run() {
        //1.孩子吃东西
        System.out.println("小刚吃完饺子了");
        //2.吃完说一声
        cdl.countDown();
    }
}
//第二个孩子
public class MyChildThread2 extends Thread {
    private CountDownLatch cdl;

    //利用构造方法,来给cdl赋值
    public MyChildThread2(CountDownLatch cdl) {
        this.cdl = cdl;
    }

    @Override
    public void run() {
        //1.孩子吃东西
        System.out.println("小黄吃完饺子了");
        //2.吃完说一声
        cdl.countDown();
    }
}
//妈妈线程,等待前面两个孩子线程执行完毕之后再执行。
public class MyMother extends Thread{
    private CountDownLatch cdl;
    //利用构造方法,来给cdl赋值
    public MyMother(CountDownLatch cdl) {
        this.cdl = cdl;
    }

    @Override
    public void run() {
        //1.先等待
        try {
            cdl.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //2.收拾碗筷
        System.out.println("吃完饭洗完"); 
    }
}

测试类

public static void main(String){
    //创建一个CountDownLatch对象,记录执行的线程数量
    CountDownLatch cd = new CountDownLatch(2);
    //三个线程共用一个CountDownLatch对象(计数器)
    new MyMother(cd).start();
    new MyChildThread1(cd).start();
    new MyChildThread2(cd).start();
}

Semaphore类

SemaPhore类用来控制正在执行的线程数量,相当于一个管理员的角色,它可以给线程发许可证,得到许可证的线程才能执行,没有得到许可证的线程就必须等待。通过SemaPhore的构造方法,可以指定有多少个线程获得许可。

 public class MyRunnable implements Runnable{
    //创建对象,控制线程执行的数量为2
    Semaphore sp = new Semaphore(2); 
    @Override
    public void run(){
        try {
            //发同行许可
            sp.acquire(); 

            //线程执行的代码
            System.out.println(Thread.currentThread().getName()+"执行了");
            Thread.sleep(3000);

            //释放同行许可
            sp.release();

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
public class Demo6 {
    public static void main(String[] args) {
        MyRunnable mr=new MyRunnable();

        for (int i = 0; i < 100; i++) {
            new Thread(mr,"线程"+i).start();
        }
    }
}

Go语言高级编程: 多线程、协程相关的高级主题 2021年Go语言已经成为非常流行的系统级编程语言,其提供了高效灵活的并发模型(包括 goroutine 和 channel),极大的提升了开发效率。因此,对于想要进一步提升自身能力的工程师来说,掌握Go语言的一些高级特性也是至关重要的。本系列文章将从多线程到协程,详细介绍并实践Go语言中的各种高级特性,帮助读者更好地理解并使用这些特性进行系统编程。在阅读本系列文章之前,建议读者对Go语言有所了解,并且熟练使用Go语言进行编程。本系列文章基于Go1.17版本编写,与更新版本的语法及特性有所差异。 阅读详情

相关推荐

Java线程 高级使用

Java线程 高级使用线程 Java线程

多线程(二)---高阶篇

一.CAS 1.概述 (1)技术背景 线程执行的任务,任务量比较小的时候,线程安全需要使用synchronized(多个线程同时竞争对象锁)加锁,效率比较低(竞争失败的线程很快的在阻塞态和被唤醒状态之间切换) (2)使用前提 代码执行速度非常快 (3)目的 在安全的前提下优化效率—使用较多的场景:对变量修改保证线程安全 (4)原理 使用CAS,不造成线程阻塞(一直处于运行态) 2.什么是CAS 全称Compare and swap,即比较并交换 当多个线程同时对某个资源进行CAS操作,只能有一个线程操作成功

liyuuhuvnjjv的博客 389

Vivado SDK中LWIP库版本冲突与RTL8211FDI兼容性实战解析

本文深入解析Vivado 2019.1 SDK中LWIP 1.0库与RTL8211FDI千兆PHY芯片的版本冲突问题,并提供实战解决方案。通过手动移植高版本LWIP库、整合第三方驱动及优化BSP配置,有效解决了以太网通信兼容性问题,确保千兆性能稳定运行。

ios99的博客 272

多线程——多线程高级

生产者消费者案例 自己实现等待和唤醒 由于CPU的随机性,多个线程在执行的时候是在相互抢夺CPU的执行权。为了让多个线程协同工作,可使用等待和唤醒机制。 消费者和生产者案例就是一个很经典的,利用等待和唤醒,让多个线程达到协同工作的效果。满足的是一种供需关系。 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pM6jSBZ8-1612402231375)(assets/1603508136981.png)] //桌子 public class Desk { //默认生产1

渺万里层云 327

数字IC设计技能篇之如何在RTL级降低功耗?

以上就是本次降低芯片功耗的部分心得和收获,由于是在芯片设计阶段还没办法后端直接给出power的报告,前端一般使用spyglass和fsdb来进行功耗分析,后续会更新如何使用spyglass在前仿阶段进行power的分析,以及持续更新有关RTL级降低功耗的相关内容。

mzynk的博客 1202

PCB线路板的制作工艺流程分享!2021-08-21

Pcb板制作工艺流程:开料-钻孔-沉铜-压膜-曝光-显影-电铜-电锡-退膜-蚀刻-退锡-光学检测-印阻焊油-阻焊曝光、显影-字符-表面处理-成型-电测-终检-抽测-包装。具体如下:1、开料(CUT) 将原始的覆铜板切割成可以用在生产线上制作的板子过程2、钻孔 使PCB板层间产生通孔,以达到连通层间的目的。 3、沉铜 经过钻孔后的线路板在沉铜缸内会发生氧化还原反应,形成铜层对孔进行孔金属化,使原来绝缘的基材表面沉积上铜,达到层间电性相通。 4、压膜 压膜后的PCB板上面压了一层蓝色的干膜, 干膜是一个载体

jdbpcb88的博客 3246

【实战总结】线程池异常处理策略

简单谈谈线程池在使用过程中出现异常的一些处理策略,合理使用线程池,必须能够识别主线程与线程池直接的关系、充分了解线程池机制,发挥优点,了解盲区,合理利用不留坑。 先demo几个例子,有时间展开论述下使用场景和异常处理。 /** * created by guanjian on 2020/6/18 15:30 */ public class ThreadPoolExecutorTest extends BaseTest { @Resource private ThreadPool

大摩羯先生 800

程序化广告行业(2/89):从程序化广告深挖数据处理技巧

大家好!我一直希望能和大家在技术学习的道路上携手共进,这也是我写这一系列博客的初衷。上次我们一起学习了Python基础的数据处理知识,这次咱们借助一本程序化广告手册,深入挖掘数据处理的更多技巧。这本手册涵盖了程序化广告从概念到技术实现的诸多方面,而其中处处都涉及到数据处理,相信会给我们带来不少收获

yyy173611的博客 4572

java多线程基础篇---并发工具类

文章目录并发工具类Fork-Join分而治之工作窃取CountDownLatchCyclicBarrierSemaphoreExchanger转载申明 并发工具类 Fork-Join Fork-Join是一个分儿治之,工作窃取的框架,他是jdk1.7之后加入的一个处理并发的框架。什么是分而治之?什么又是工作窃取?看下面。 分而治之 把工作拆分成多份,分别处理的思想。比如超市排队,现在有100个人只有一个付款通道,如果一个通道需要2分钟,那总的时间就是200分钟。如果这时候加入4个通道变成5通道,100个人分

qq_36124777的博客 347

从工具选型到落地实践:吃透 SAP Fiori Launchpad 配置工具体系

摘要: SAP Fiori Launchpad配置远非简单添加应用和分配角色,涉及技术目录、业务目录、Spaces/Pages等多层管理。官方推荐新工具分工:技术目录用FLPAM维护应用定义,业务目录用FLPCM编排应用组合,Spaces/Pages优化用户体验布局,而传统Groups模式已被标记弃用。这种分层治理模式(定义层-编排层-展示层)能有效解决传输混乱、升级兼容性问题,尤其适合大规模项目实施。关键在于区分技术配置与业务呈现,避免将所有功能堆砌在单一旧工具中。(149字)

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 103

YOLO26引入ECA-Net的改进版变体:1D卷积在2026目标检测的极致压榨

摘要: 2026年发布的YOLO26通过移除DFL模块、支持无NMS推理等革新成为边缘计算新标杆。为进一步提升性能,研究聚焦轻量级通道注意力机制ECA-Net,其核心创新在于用1D卷积替代传统全连接层,仅需5个参数即可实现高效通道交互。数学分析表明,ECA模块在ResNet50上仅增加80个参数,却能带来2%以上的精度提升。这种"极致压榨"的设计理念与YOLO26的轻量化特性高度契合,为在几乎不增加计算开销的前提下提升模型性能提供了可行方案。技术验证显示,该组合在COCO数据集上实现了检测精度与推理效率的双

ZDQ58818的博客 262

线程同步的辅助类

countDownLatch是java.util.cucurrent下的一个类,这个类可以实现线程的同步阻塞。 通过一个计数器来实现,计数器的初始值是可以设置成线程的数量。每当一个线程执行完毕后,计数器的值就-1,当计数器的值为0时,表示所有线程都执行完毕,然后在闭锁上等待的线程就可以恢复工作了。 leetCode: https://leetcode-cn.com/problems/print-in-order/ ...

CarryBest的博客 474

几种在NCBI中查询获取目的基因序列的方法

几种在NCBI中查询获取目的基因序列的方法 在NCBI中,如何查询并下载获得某物种的某特定功能的基因序列,相信对于看到此篇的大部分同学来说都不陌生了。想到对于刚开始接触生信的同学们来说,也许尚不能很熟练地在NCBI中查询想要的基因序列,因此在这里简要作了一个总结,希望对初学生信的同学们有所帮助。 此篇博文源于此前有同学问我,提到他导师给他布置任务,查找相关的文献,看相关文献中都报道了哪些细菌物种能够产生聚羟基脂肪酸酯(polyhydroxyalkanoate ,PHA),参与合成该产物的基因都有哪些,然后在

qq_23435961的博客 1万+

QT多线程高级编程

线程概述《QT多线程高级编程》正文,线程概述在现代软件开发中,多线程编程已经成为了一项不可或缺的技能。特别是在嵌入式系统、实时系统和图形界面应用程序中,线程的使用能够显著提高程序的性能和用户体验。Qt框架作为一款功能强大的跨平台C++图形用户界面库,为开发者提供了丰富的线程使用方式。线程的基本概念线程,也被称作轻量级进程(Lightweight Process),是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。

QT性能优化QT原理源码QT界面美化 1119

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

Python高级培训:多线程

个人对Python多线程的一些理解,希望对大家有帮助

m0_57077614的博客 522

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

【QT】Qt多线程编程之高级函数

【QT】Qt多线程编程之高级函数 1. 概述 之前的文章我们都是讨论 QThread 这种很底层的类,使用起来要考虑方方面面。或者说只要用到底层的接口(如 QThread、信号量、互斥锁等),那基本就是重新造一个轮子出来。幸运的是,Qt 提供了高级函数来简化我们的多线程编写,它就是 Qt Concurrent 模块! 只要在 pro 文件添加“Qt += concurrent”并且在我们的 h 文件添加“#include ”,就可以使用这些函数了。基本上所有的 concurrent 函数分为三种类型: r

qq_43331089的博客 2172

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

7.Java高级编程 多线程

3.实现Callable,重写call方法 **注意:**Callable有返回值。​ 实现了Map接口,Hashtable继承Dictionary类。2.实现Runnable接口,重写run方法,创建Thread对象。​ 继承关系实现了Map接口,继承AbstractMap类。​ 继承关系实现了Map接口,继承AbstractMap类。1.继承Thread类,重写run方法,调用start方法。ArrayList类的add()方法为非同步方法。

QAZ412803的博客 1451

Python中的多线程高级使用

在Python中,多线程是一种使程序能够同时执行多个任务的技术。🚀尽管Python的全局解释器锁(GIL)限制了线程的并行执行,但多线程仍然是IO密集型任务和提升用户界面响应性的有效手段。本文将深入探讨Python中多线程的高级用法,从基本知识点到高级技巧,助力开发者充分利用多线程的强大功能。

weixin_68789096的博客 904

多线程的基础与高级

多线程的基础与高级

ljbnb的博客 321

提高性能的艺术:Python中的高级多线程应用

通过本文,我们不仅学习了Python中多线程的基础知识、同步机制和实际应用,还简要介绍了多线程编程的最佳实践和注意事项。多线程编程是一个复杂但极富挑战性的领域,正确地使用多线程可以显著提高程序的性能和响应速度。然而,多线程编程也带来了数据安全、死锁和调试等问题。开发者需要仔细设计线程间的交互,合理地使用同步机制,以确保程序的稳定性和高效性。此外,随着技术的不断进步,新的并发编程模型和工具不断涌现,持续学习和实践是提高自身技能的关键。

walkskyer的博客 1831

【day18】多线程高级应用

Lock是一个接口,其实现类为,提供了比更灵活的锁控制。lock():获取锁。unlock():释放锁。//定义100张票//创建Lock对象@Overridetry {//获取锁System.out.println(Thread.currentThread().getName() + "买了第" + ticket + "张票");ticket--;}finally {//释放锁Thread t1 = new Thread(myTicket, "赵四");

程序员波特 1004

基于多线程应用的高级消费者(kafka)

从Kafka读取消息的逻辑并不关心处理消息偏移量,它只需要数据。因此,高级消费者可以从Kafka中抽象出消费事件的大部分细节。 线程模型围绕主题的分区数,有一些具体的规则: 如果线程多于主题上的分区,那么有些线程将永远不会看到消息 如果分区比线程多,一些线程将从多个分区接收数据 如果每个线程有多个分区,则无法保证接收消息的顺序,除非在分区中偏移量是顺序的。例如,从分区1接收到5条消息,...

小浩子的博客 1248

Qt高级编程之多线程处理

周末在图书馆不经意间翻阅了《Qt高级编程》后就爱释手,作者Mark Summerfield高瞻远瞩、思路清晰,刚好满足我提升Qt知识的需要,于是立马从图书馆借出,舔了三月。一个处理器划分为若干个短的时间片,每个时间片依次轮流地执行处理各个应用程序,由于一个时间片很短,相对于一个应用程序来说,就好像是处理器在为自己单独服务一样,从而达到多个应用程序在同时进行的效果。

weixin_38880029的博客 2650

Java的三魂七魄 —— 高级多线程

Java的三魂七魄之一:多线程。本文章带你了解多线程的多个知识点,包括多线程的创建、线程安全问题、线程通信问题...

weixin_44217612的博客 1766

多线程之线程高级

1.生产者消费者模型 技术点: 多线程模型,安全锁机制,等待与唤醒 /** 多线程 生产与消费模型: 分析: 1,创建生产者类继承Thread,只负责生产 2. 创建消费者类继承Thread,只负责消费 3. 两个线程共同操作仓库类Store 4. 加入安全锁及等待与唤醒机制 问题1:生产两个动作,消费也是两个动作,当你打印生产,还没加库存;就已经消费了,库存值不对 处理:加锁 ,解决生产与消费的数据混乱 问题2: 仓满和仓空的限制 处理: 限制...

Yeung_ZY的博客 1683
上一篇: 多线程基础
下一篇: 网络编程
Figure_TheKeyboard
博客等级 码龄5年 6粉丝 36原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值