Java(八)----多线程(二)

news2025/1/11 11:40:41

1. 生产者与消费者

1.1 安全问题产生

  • 线程本身就是一个新创建的方法栈内存 (CPU进来读取数据)

  • 线程的notify(),唤醒第一个等待的线程

    • 解决办法 : 全部唤醒 notifyAll()

  • 被唤醒线程,已经进行过if判断,一旦醒来继续执行

    • 线程被唤醒后,不能立刻就执行,再次判断标志位,利用循环

    • while(标志位) 标志位是true,永远也出不去

/**
 * 定义资源对象
 *   成员 : 产生商品的计数器
 *          标志位
 */
public class Resource {
   private int count ;
   private boolean flag ;

   //消费者调用
   public synchronized void getCount() {
         //flag是false,消费完成,等待生产
         while (!flag)
            //无限等待
            try{this.wait();}catch (Exception ex){}
         System.out.println("消费第"+count);
            //修改标志位,为消费完成
         flag = false;
         //唤醒对方线程
         this.notifyAll();
   }
   //生产者调用
   public synchronized void setCount() {
         //flag是true,生产完成,等待消费
       while (flag)
            //无限等待
            try{this.wait();}catch (Exception ex){}
         count++;
         System.out.println("生产第"+count+"个");
         //修改标志位,为生产完成
         flag = true;
         //唤醒对方线程
         this.notifyAll();
   }
}
/**
 * 生产者线程
 *   资源对象中的变量++
 */
public class Produce implements Runnable{

    private Resource r ;

    public Produce(Resource r) {
        this.r = r;
    }

    @Override
    public void run() {
        while (true) {
            r.setCount();
        }
    }
}
/**
 * 消费者线程
 *   资源对象中的变量输出打印
 */
public class Customer implements Runnable{
    private Resource r ;

    public Customer(Resource r) {
        this.r = r;
    }

    @Override
    public void run() {
        while (true) {
            r.getCount();
        }
    }
}
    public static void main(String[] args) {
        Resource r = new Resource();
        //接口实现类,生产的,消费的
        Produce produce = new Produce(r);
        Customer customer = new Customer(r);
        //创建线程
        new Thread(produce).start();
        new Thread(produce).start();
        new Thread(produce).start();
        new Thread(produce).start();
        new Thread(produce).start();
        new Thread(produce).start();
        new Thread(customer).start();
        new Thread(customer).start();
        new Thread(customer).start();
        new Thread(customer).start();
        new Thread(customer).start();
        new Thread(customer).start();
    }

1.2 线程方法sleep和wait的区别

  • sleep()在休眠的过程中,同步锁不会丢失 ,不释放

  • wait()等待的时候,发布监视器的所属权, 释放锁.唤醒后要重新获取锁,才能执行

1.3 生产者和消费者案例性能问题

wait()方法和notify()方法, 本地方法调用OS的功能,和操作系统交互,JVM找OS,把线程停止. 频繁等待与唤醒,导致JVM和OS交互的次数过多.

notifyAll()唤醒全部的线程,也浪费线程资源,为了一个线程,不得以唤醒的了全部的线程.

1.4 Lock接口深入

Lock接口替换了同步synchronized, 提供了更加灵活,性能更好的锁定操作

  • Lock接口中方法 : newCondition() 方法的返回值是接口 : Condition

1.5 生产者与消费者改进为Lock接口

  • Condition接口 (线程的阻塞队列)

    • 进入队列的线程,释放锁

    • 出去队列的线程,再次的获取锁

    • 接口的方法 : await() 线程释放锁,进入队列

    • 接口的方法 : signal() 线程出去队列,再次获取锁

线程的阻塞队列,依赖Lock接口创建

/**
 *  改进为高性能的Lock接口和线程的阻塞队列
 */
public class Resource {
   private int count ;
   private boolean flag ;
   private Lock lock = new ReentrantLock();//Lock接口实现类对象

    //Lock接口锁,创建出2个线程的阻塞队列
    private Condition prod = lock.newCondition();//生产者线程阻塞队列
    private Condition cust = lock.newCondition();//消费者线程阻塞队列

   //消费者调用
   public  void getCount() {
       lock.lock();//获取锁
         //flag是false,消费完成,等待生产
         while (!flag)
            //无限等待,消费线程等待,执行到这里的线程,释放锁,进入到消费者的阻塞队列
             try{cust.await();}catch (Exception ex){}

         System.out.println("消费第"+count);
            //修改标志位,为消费完成
         flag = false;
         //唤醒生产线程队列中的一个
         prod.signal();
         lock.unlock();//释放锁
   }
   //生产者调用
   public  void setCount() {
       lock.lock();//获取锁
         //flag是true,生产完成,等待消费
       while (flag)
            //无限等待,释放锁,进入到生产线程队列
            try{prod.await();}catch (Exception ex){}
         count++;
         System.out.println("生产第"+count+"个");
         //修改标志位,为生产完成
         flag = true;
         //唤醒消费者线程阻塞队列中年的一个
         cust.signal();
       lock.unlock();//释放锁
   }
}

1.6 Lock锁的实现原理

使用技术不开源,技术的名称叫做轻量级锁

使用的是CAS锁 (Compare And Swap) 自旋锁

JDK限制 : 当竞争的线程大于等于10,或者单个线程自旋超过10次的时候

JDK强制CAS锁取消.升级为重量级锁 (OS锁定CPU和内存的通信总线,只有一个线程通过)

2. 单例设计模式

设计模式 : 不是技术,是以前的人开发人员,为了解决某些问题实现的写代码的经验.

所有的设计模式核心的技术,就是面向对象.

Java的设计模式有23种,分为3个类别,创建型,行为型,功能型

 (此博客中单例模式)

Java-设计模式-(三)单例模式(创建型模式)_YounG_tt33的博客-CSDN博客

2.3 关键字volatile

成员变量修饰符,不能修饰其它内容

  • 关键字作用 :

    • 保证被修饰的变量,在线程中的可见性

    • 防止指令重排序

      • 单例的模式, 使用了关键字,不使用关键字,可能线程会拿到一个尚未初始化完成看的对象(半初始化)

3. 线程池ThreadPool

线程的缓冲池,目的就是提高效率. new Thread().start() ,线程是内存中的一个独立的方法栈区,JVM没有能力开辟内存空间,和OS交互.     (缓冲池技术)

JDK5开始内置线程池      类比数据库连接池(Connection)

3.1 Executors

  • 静态方法static newFixedThreadPool(int 线程的个数)  输入int后创建线程池固定,扩容则会创建新的线程池

    • 方法的返回值ExecutorService接口的实现类,管理池子里面的线程

  • ExecutorService接口的方法

    • submit (Runnable r)提交线程执行的任务

3.2 Callable接口

实现多线程的程序 : 接口特点是有返回值,可以抛出异常 (Runnable没有)

抽象的方法只有一个, call

启动线程,线程调用重写方法call

  • ExecutorService接口的方法

    • submit (Callable c)提交线程执行的任务

    • Future submit()方法提交线程任务后,方法有个返回值 Future接口类型

    • Future接口,获取到线程执行后的返回值结果 

public class MyRunnable implements Runnable {
    @Override
    public void run() throws Exception{
        sout("线程开始启动");
    }
}
public class MyCall implements Callable<String> {
    public String call() throws Exception{
        return "返回字符串";
    }
}
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //创建线程池,线程的个数是2个
       ExecutorService  es =  Executors.newFixedThreadPool(2);
       //线程池管理对象service,调用方法啊submit提交线程的任务
        MyRunnable my = new MyRunnable();
        //提交线程任务,使用Callable接口实现类
        Future<String> future = es.submit(new MyCall());//返回接口类型 Future
        //接口的方法get,获取线程的返回值
        String str = future.get();
        System.out.println("str = " + str);

//        es.submit(my);
//        es.submit(my);
//        es.submit(my);
       // es.shutdown();//销毁线程池
    }

4. ConcurrentHashMap

ConcurrentHashMap类本质上Map集合,键值对的集合.使用方式和HashMap没有区别.

凡是对于此Map集合的操作,不去修改里面的元素,不会锁定

5. 线程的6种状态图-生命周期

在某一个时刻,线程只能处于其中的一种状态. 这种线程的状态反应的是JVM中的线程状态和OS无关.

 

TIMED_WAITING:sleep()与wait():sleep()不释放锁,时间结束后继续执行;wait()会释放锁,时间结束后wait()若拿不到锁会转为阻塞状态BLOCKED。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/54036.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[附源码]Python计算机毕业设计Django基于Vue的社区拼购商城

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

Python学习日记-第三十八天-生成器

系列文章目录 生成器创建生成器的方法生成器-使用send方式唤醒使用yield完成多任务一、生成器 利用迭代器&#xff0c;我们可以在每次迭代获取数据&#xff08;通过next方法&#xff09;时按照特定的规律进行生成&#xff0c;但是我们在实现一个迭代器时&#xff0c;关于当前…

Pr:导出设置之基本视频设置

视频 VIDEO设置因所选导出格式而异。每种格式都有独特的要求&#xff0c;这些要求决定了哪些设置可用。以导出文件格式为 H.264 为例&#xff0c;下面给出有关基本视频设置 Basic Video Settings的选项及说明。匹配源Match Souce自动设定视频设置选项以匹配源视频的属性。支持匹…

项目一共30个模块,你叫我maven版本一个个手动改?

之前有个群友私聊问我&#xff0c;如何快速统一去更改项目中所有的maven版本号&#xff0c;他说之前都是手动一个个去修改&#xff0c;项目一共有30多个maven模块&#xff0c;上次因为漏改了一个&#xff0c;还造成了生产事故。 其实我自己开源项目有的工程也非常多&#xff0…

Java入门必备知识你能掌握多少?

1、Java是一种高级计算机语言&#xff0c;是可以编写跨平台应用软件、完全面向对象的程序设计语言。 2、Java划分为三个技术平台&#xff1a;Java SE、Java EE、Java ME Java SE是桌面应用&#xff0c;Java EE是web应用&#xff0c;平台企业版&#xff0c;Java ME是手机应用&…

亚马逊鲲鹏系统批量注册功能可以让你快速拥有大量亚马逊买家号

亚马逊鲲鹏系统是一款能批量注册买家号、AI智能一键养号、模拟真人行为轨迹进行刷单测评的软件&#xff0c;而对于批量注册买家号&#xff0c;操作也是比较简单的。 主要流程是购买了相应的账号所需资料后&#xff0c;通过批量导入邮箱、邮箱密码、信用卡、收货地址进入软件然后…

嵌入式分享合集114

一、DMA DMA&#xff0c;全称Direct Memory Access&#xff0c;即直接存储器访问。 DMA传输将数据从一个地址空间复制到另一个地址空间&#xff0c;提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。 我们知道CPU有转移数据、计算、控制程序转移等很多功能&…

拿到8000元的火焰杯比赛奖金,感谢霍格沃兹测试开发学社

下面是我们获奖学员自己主动分享的 然后发给霍格沃兹测试开发学社表示感谢的&#xff0c;收到她的反馈我们也由衷的开心。所以也分享给大家&#xff0c;目前无论是应届生 在校生还是从业人员&#xff0c;都可以加入第三届火焰杯比赛&#xff0c;赢取属于专属于自己的荣耀。 我…

学生HTML个人网页作业作品:基于HTML实现教育培训机构网站模板毕业源码(8页)

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

[附源码]JAVA毕业设计霍山石斛网站(系统+LW)

[附源码]JAVA毕业设计霍山石斛网站&#xff08;系统LW&#xff09; 目运行 环境项配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&…

AutoJs7打包薅羊毛时间版

AutoJs7打包薅羊毛时间版 一、准备工作&#xff1a; autojs7 app 下载地址&#xff1a;Auto.js Pro7.apk - 蓝奏云薅羊毛时间版 下载地址&#xff1a; 亚丁号---文件下载 安卓手机一部外加数据线&#xff08; Type-C或者USB&#xff09;&#xff0c;最好是安卓7的系统。电脑…

云服务器购买流程

云服务器购买流程 在技术学习的路上&#xff0c;除了虚拟机外最贴近实战的机器就是服务器。实际上在企业中有些小企业用的也是租赁的云服务器&#xff0c;有些是自己公司搭建的服务器。不管什么服务器了&#xff0c;实际上都是一样的&#xff0c;如果想更靠近企业级开发&#x…

Kotlin高仿微信-第52篇-搜索好友

Kotlin高仿微信-项目实践58篇详细讲解了各个功能点&#xff0c;包括&#xff1a;注册、登录、主页、单聊(文本、表情、语音、图片、小视频、视频通话、语音通话、红包、转账)、群聊、个人信息、朋友圈、支付服务、扫一扫、搜索好友、添加好友、开通VIP等众多功能。 Kotlin高仿…

HTTP

文章目录一、HTTP 基本概念GET 与 POSTHTTP 特性HTTP 与 HTTPSHTTP/1.1、HTTP/2、HTTP/3 演变HTTP/1.1如何优化如何避免发送 HTTP 请求&#xff1f;如何减少 HTTP 请求次数减少重定向请求次数合并请求延迟发送请求如何减少 HTTP 响应的数据⼤⼩&#xff1f;⽆损压缩有损压缩HTT…

YGG 和 BlockchainSpace 举办全国最大的 Web3 活动:Philippine Web3 Festival

2022 年 11 月 14 日至 18 日&#xff0c;Yield Guild Games (YGG) 和 BlockchainSpace 在菲律宾共同举办了迄今为止最大的 web3 活动&#xff0c;汇集了来自世界各地的游戏玩家、建设者、投资者、开发者、教育工作者和艺术家加入 web3 的应用。该活动吸引了来自 web3 社区的数…

计算机网络——TCP/IP模型

OSI参考模型与TCP/IP标准模型 OSI模型先出现理论&#xff0c;并没有实践&#xff0c;只是一个法定参考模型。 TCP/IP模型出现早&#xff0c;应用早。TCP/IP模型其实是先诞生一个协议栈。 再出现TCP/IP参考模型 TCP/IP模型中的网络接口层其实是把数据链路层和物理层进行合并了…

电脑桌面文件不见了怎么恢复?

众所周知&#xff0c;我们都会在电脑桌面上放置各种文件、文件夹等&#xff0c;这样很容易造成文件堆积过多&#xff0c;桌面杂乱无章&#xff0c;影响查找文件速度。这不可避免的要对电脑桌面进行整理&#xff0c;但有时候我们会出现重要文件突然就找不到了&#xff0c;这时电…

RabbitMQ延时队列

延时队列内部是有序的&#xff0c;最重要的特性就是延时&#xff0c;延时队列中的元素是希望在指定时间到了以后或之前取出和处理&#xff0c;简单来说&#xff0c;延时队列就是用来存放需要在指定时间被处理的元素的队列。 使用场景 订单在十分钟之内未支付则自动取消新创建…

新上线软件需不需要防御?

导语&#xff1a;随着5G时代到来和ipv6的普及&#xff0c;攻击者手段层出不穷&#xff0c;从一开始简单的DDOS分布式拒绝服务&#xff0c;后到蔓延ACK 从不同协议通讯层面发起的攻击&#xff0c;现在CC请求类型攻击&#xff0c;已经可以绕过域名验证&#xff0c;以及模拟正常用…

css实现价格降价线

比较简单&#xff0c;直接上代码 <div class"container"><div>今日价格&#xff1a;$9.99</div><div>商品原价&#xff1a;<span class"price">$49.99</span></div> </div>.price {text-decoration: lin…