Java-Java基础学习(4)-多线程(2)

3.7. Lambda表达式

  1. 为什么要使用lambda表达式

    • 避免匿名内部类定义过多;
    • 可以让代码看起来更简洁;
    • 去掉一堆没有意义的代码,只留下核心逻辑
  2. 属于函数式编程的概念,格式

    • (params) -> expression [表达式]
    • (params) -> statement [语句]
    • (params) -> {statements}
  3. 函数式接口

    • 任何接口,只有唯一一个抽象方法,就是一个函数式接口
    • 对于函数式接口,可以通过Lambda表达式来创建该接口的对象
  4. 测试

    TestLambda.java
        
    package com.hzs.basic.multithread;
    
    /**
     * @author Cherist Huan
     * @version 1.0
     */
    public class TestLambda {
    
        // 2、静态内部类
        static  class Like2 implements Ilike{
    
            @Override
            public void lambda() {
                System.out.println("Like-->2");
            }
        }
    
        public static void main(String[] args) {
            Ilike like = null;
    
            // 1、外部实现类1
            like = new Like();
            like.lambda();
    
            // 2、静态内部类
            like = new Like2();
            like.lambda();
    
            //3、局部内部类
            class Like3 implements Ilike{
    
                @Override
                public void lambda() {
                    System.out.println("Like-->3");
                }
            }
            like = new Like3();
            like.lambda();
    
            //4、匿名内部类,没有类的名称,必须借助接口或父类
            like = new Ilike() {
                @Override
                public void lambda() {
                    System.out.println("Like-->4");
                }
            };
           like.lambda();
    
           //5、用Lambda表达式
            like = ()->{
                System.out.println("Like-->5");
            };
            like.lambda();
        }
    }
    
    // 1、定义一个函数式接口
    interface Ilike{
        void lambda();
    }
    
    // 2、外部实现类1
     class Like implements Ilike{
    
        @Override
        public void lambda() {
            System.out.println("Like-->1");
        }
    }
    
    
  5. a

3.8. 线程的状态(5种)

在这里插入图片描述

线程工包括5中状态:

  • 新建状态(New):线程对象被创建后,就进入了新建状态。例如:,Thread thread = new Thread().

  • 就绪状态(Runnable):也被称为“可执行状态”。线程对象被创建后,其它线程调用了该对象的start()方法,从而来启动该线程。例如:thread.start()。处于就绪状态的线程,随时可能被CPU调度执行。

  • 运行状态(Running):线程获取CPU权限进行执行。需要注意的是,线程只能从就绪状态进入到运行状态

  • 阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。

    阻塞的情况分3种:

    • 等待阻塞:通过调用线程的wait()方法,让线程等待某工作的完成;
    • 同步阻塞:线程在获取synchronized同步锁失败(因为锁被其他线程所占用),它会进入同步阻塞状态;
    • 其他阻塞:通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
  • 死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

3.9.线程同步

  • 同步方法

    • synchronized关键字,它包括synchronized方法和synchronized块

      同步方法: public synchronized void method(int args){}
      
    • synchronized方法控制对“对象”的访问,每个对象对应一把锁,每个synchronized方法都必须获得调用该方法的对象的锁才能执行,否则线程会阻塞,方法一旦执行,就独占该锁,指导该方法返回是释放锁,后面被阻塞的线程才能获得这个锁,继续执行。

    • 缺陷:若将一个大的方法声明为synchronized将会影响效率

  • 同步块

    • 同步块:synchronized (Obj){}

    • Obj称之为同步监视器

      • Obj可以是任何对象,但是推荐使用共享资源作为同步监视器
      • 同步方法中无需指定同步监视器,因为同步方法的同步监视器就是this,就是这个对象本身,或者是class(反射);
    • 同步监视器的执行过程:

      • 1.第一个线程访问,锁定同步监视器,执行其中代码;
      • 2.第二个线程访问,发现同步监视器被锁定,无法访问;
      • 3.第一个线程访问完毕,解锁同步监视器;
      • 4.第二个线程访问,发现同步监视器没有锁,然后锁定并访问。
    • 锁Obj例子

      UnsafeList.java
      package com.hzs.basic.multithread;
      import java.util.ArrayList;
      import java.util.List;
      
      /**
       * @author Cherist Huan
       * @version 1.0
       */
      public class UnsafeList {
          public static void  main(String[] args)  {
              List<String> list = new ArrayList<String>();
      
              for (int i = 0; i < 10000; i++) {
                  new  Thread(()->{
                              synchronized  (list){
                                  list.add(Thread.currentThread().getName());
                              }
                          }).start();
              }
              // 获取线程数目
              boolean flag = true;
              while(flag){
                  if(Thread.activeCount() <= 2)
                  {
                      flag = false;
                      System.out.println(list.size());
                  }
              }
          }
      }
      
      

3.10.死锁

产生死锁的4个必要条件:

  • 互斥条件:一个资源每次只能被一个进程使用;
  • 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放;
  • 不剥夺条件:进程已获得的资源,在未使用完之前,不能强行剥夺;
  • 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系

避免死锁,只要破坏上面至少一个条件即可。

3.11.Lock锁

  • 格式

    class A{
        private  final   ReentrantLock lock  = new ReentrantLock();
        
        public void method(){
            lock.lock();
            try{
                //保证线程安全的代码
            }finally{
                lock.unlock();
            }
        } 
    }
    
  • 例子

    package com.hzs.basic.multithread;
    import java.util.concurrent.locks.ReentrantLock;
    /**
     * @author Cherist Huan
     * @version 1.0
     */
    public class TestLock {
        public static void main(String[] args) {
            Ticket ticket = new Ticket();
    
            new Thread(ticket).start();
            new Thread(ticket).start();
            new Thread(ticket).start();
    
        }
    }
    
    class Ticket implements Runnable{
    
        private  int ticketNum = 10;
        private  final   ReentrantLock reentrantLock  = new ReentrantLock();
        @Override
        public void run() {
            while(true) {
                // 加锁
                reentrantLock.lock();
                try {
                    if(ticketNum > 0)
                    {
                        Thread.sleep(100);
                        System.out.println(ticketNum--);
                    }else{
                        break;
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    reentrantLock.unlock();
                }
            }
        }
    }
    
    
  • synchronized与Lock的对比

    • Lock是显示锁(手动开启和关闭锁,别忘记关闭锁),synchronized是隐式锁,出了作用域自动释放;

    • Lock只有代码块锁,synchronized有代码块锁和方法锁;

    • 使用Lock锁,JVM将花费较少的时间来调度线程,性能更好。并且具有更好的扩展性(有很多子类,例如:可重入锁 ReentrantLock);

    • 优先使用顺序:

      Lock > 同步代码块(已经进入了方法体,分配了相应资源) > 同步方法(方法体之外)

3.12.线程通信

  1. Java提供了几个方法解决线程之间的通信问题
    • wait():表示线程一直等待,直到其他线程通知,与sleep不同,会释放锁;
    • wait(long timeout):指定等待的毫秒数;
    • notify():唤醒一个处于等待状态的线程;
    • notifyAll():唤醒同一个对象上所有调用wait()方法的线程,优先级别高的线程优先调度。
    • 注意:这些均是Object类的方法,都只能在同步方法或者同步代码块中使用,否则会抛出异常IllegalMonitorStateException

2. 等待唤醒机制:这是多个线程间的一种协作机制。

  • 谈到线程我们经常想到的是线程间的竞争(race),比如去争夺锁,但这并不是故事的全部,线程间也会有协作机制。

  • 在一个线程满足某个条件时,就进入等待状态(wait() / wait(time)), 等待其他线程执行完他们的指定代码过后再将其唤醒(notify());

  • 或可以指定wait的时间,等时间到了自动唤醒;

  • 在有多个线程进行等待时,如果需要,可以使用 notifyAll()来唤醒所有的等待线程。wait/notify 就是线程间的一种协作机制。

  1. 解决方式
  • 方式一:并发协作模型“生产者/消费者模式”-------->管程法,采用数据缓冲区
  • 方式二:并发协作模型“生产者/消费者模式”-------->信号灯法
  1. 为什么要处理线程间的通信
  • 当我们需要多个线程来共同完成一件任务,并且我们希望他们有规律的执行,那么多线程之间需要一些通信机制,可以协调它们的工作,以此实现多线程共同操作一份数据。(在同步的基础之上解决通信的问题)

  • 比如:线程A用来生产包子的,线程B用来吃包子的,包子可以理解为同一资源,线程A与线程B处理的动作,一个是生产,一个是消费,此时B线程必须等到A线程完成后才能执行,那么线程A与线程B之间就需要线程通信,即—— 等待唤醒机制。

3.13.线程池

  1. 例子

    package com.hzs.basic.multithread;
    
    import java.util.concurrent.Executor;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    /**
     * @author Cherist Huan
     * @version 1.0
     * @note 线程池的使用
     */
    public class TestThreadPool {
        public static void main(String[] args) {
            // 1、创建
            ExecutorService executorService = Executors.newFixedThreadPool(10);
    
            // 2、执行
            executorService.execute(new MyThread());
            executorService.execute(new MyThread());
            executorService.execute(new MyThread());
            
            // 3、关闭
            executorService.shutdown();
        }
    }
    
    class MyThread implements Runnable{
    
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName());
        }
    }
    输出:
    pool-1-thread-2
    pool-1-thread-1
    pool-1-thread-3
    

2、线程池工作原理图

在这里插入图片描述

3、线程池执行流程

  1. 判断核心线程数
  2. 判断任务能否加入到任务队列
  3. 判断最大线程数量
  4. 根据线程池的饱和策略除了任务(是否丢弃任务)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【教学类-44-11】20240324 杨任东竹石体 Regular(实线字体)制作的数字描字帖(AI对话大师缩略版)

作品展示 背景需求&#xff1a; 之前有三款阿拉伯数字字体&#xff0c;但是与《幼儿用数字描字簿》字体有差异 【教学类-44-05】20240201 德彪钢笔行书&#xff08;实线字体&#xff09;制作的数字描字帖-CSDN博客文章浏览阅读396次&#xff0c;点赞6次&#xff0c;收藏5次。【…

Python之Web开发中级教程----中级教程成果下载

Python之Web开发中级教程----中级教程成果下载 到目前为止&#xff0c;中级教程已经完成。 按照一步步的教程搭建虚拟机中的环境&#xff0c;包括内容如下&#xff1a; Ubuntu操作系统搭建 Python 配置 Redis 安装配置 Python库中包括 Pip安装 Pyinstaller安装 Redis安装 Jie…

strlen和sizeof

定义 strlen 和 sizeof 是 C 语言中两个用于确定字符串或数据类型大小的常用操作符&#xff0c;但它们的工作方式和目的有所不同。下面是对这两个操作符的详细解释&#xff1a; strlen strlen 是一个库函数&#xff0c;定义在 <string.h> 头文件中。它用于计算以空字符…

拥有超小型领先工艺射频微波电子元器件厂商兆讯授权世强硬创代理

射频前端芯片在模拟芯片中&#xff0c;属于进入门槛较高、设计难度较大的细分领域&#xff0c;由于国内射频前端芯片行业起步较晚&#xff0c;其市场份额主要被外企所占据&#xff0c;而在国产化浪潮的推动下&#xff0c;上游厂商的射频前端产品及技术逐渐具备领先的竞争优势。…

深度学习(三)vscode加jupyter notebook插件使用

0.前言 哎呀&#xff0c;我本次的实验是在新电脑上使用的&#xff0c;之前的笔记本上的环境什么的我都是很久以前弄好了的&#xff0c;结果到了新电脑上我直接忘了是该怎么配的了&#xff0c;不过万幸&#xff0c;花了点时间&#xff0c;查查补补&#xff0c;现在总算是可以了。…

论文汇总:A Closer Look at Few-shot Classification Again

文章汇总 文章是在总体上再一次地观察如何小样本领域存在的问题&#xff0c;并且发现了较为有趣的规律 1.测试误差随训练类别的数量而下降&#xff0c;而不是随每个类别的训练样本数量而下降。 2.训练算法(me&#xff1a;预训练模型)和自适应算法(me&#xff1a;预训练之后的…

参展企业和专业观众均创历届新高“2024杭州国际安防展会”

随着社会的不断发展&#xff0c;安防行业逐渐成为一个备受关注的领域。杭州作为中国的科技创新之城&#xff0c;一直以来都是安防行业的重要聚集地。本次展会的举办&#xff0c;不仅为参展企业提供了一个展示自身实力的平台&#xff0c;也为观众提供了一个了解安防行业最新技术…

深度解析JVM世界:JVM内存分配

本篇文章的主要内容是介绍JVM内存的分配方式、JVM内存的快速分配策略、JVM的逃逸分析和堆内存的分代思想几部分内容。 请同学们认真听讲&#xff0c;面试会问到。。。 1. 内存分配 大家需要注意不分配内存的对象无法进行其他操作 JVM 为对象分配内存的过程&#xff1a;首先…

[flask]http请求//获取请求体数据

import jsonfrom flask import Flask, requestapp Flask(__name__)app.route("/form1", methods["post"]) def form1():"""获取客户端请求的请求体[表单]:return:""""""获取表单数据请求url&#xff1a;&qu…

[深度学习]yolov8+streamlit搭建精美界面GUI网页设计源码实现三

【设计思路介绍】 为了使用YOLOv8和Streamlit搭建一个精美的界面GUI网页&#xff0c;你需要遵循几个关键步骤。以下是一个简化的流程&#xff0c;帮助你设计并实现这一目标&#xff1a; 1. 环境准备 安装YOLOv8 YOLOv8是一个先进的实时目标检测模型。你需要先下载并安装YOL…

Android Studio 代理

Android Studio的代理&#xff0c;分为两级代理&#xff1a; 1. Android Studio本身的代理&#xff0c;路径在&#xff0c;右上角&#xff0c;File->Settings->Appearance & Behavior -> System Settings -> Http Proxy&#xff0c;如图所示&#xff1a; 2. G…

Mybatis中QueryWrapper的复杂查询SQL

最近在使用QueryWrapper编写查询语句时发现复杂的SQL不会写。在网上找了半天&#xff0c;终于得到了点启示。在此做个记录以备忘。 我要实现的SQL是这样的&#xff1a; -- 实现这个复杂查询 -- 查询设备表 select * from oa_device where ((dev_code BSD1003 and dev_status…

护眼灯有没有必要买?多款高口碑护眼台灯推荐

我发现目前仍有很多家长都忽视了环境光的重要性&#xff0c;在孩子学习的时候习惯只开家里的吸顶灯提供作业&#xff0c;但其实环境光线的不足&#xff0c;对孩子的眼镜危害是非常大的&#xff01;也有家长问护眼灯有没有必要买&#xff1f; 我认为是很有必要的&#xff01;因…

基于java+SpringBoot+Vue的乐校园二手书交易管理系统设计与实现

基于javaSpringBootVue的乐校园二手书交易管理系统设计与实现 开发语言: Java 数据库: MySQL技术: SpringBoot MyBatis工具: IDEA/Eclipse、Navicat、Maven 系统展示 前台展示 后台展示 系统简介 整体功能包含&#xff1a; 乐校园二手书交易管理系统是一个基于互联网的二…

纹理压缩算法

一、什么是纹理压缩 我们知道游戏中对于3D物体表面细节的表现最重要的还是靠贴图来实现的&#xff0c;那么越是高分辨率越是真彩色的贴图自然表现力也是越强&#xff0c;但是同时带来的问题是所需占用的内存会成倍的上升&#xff0c;而节省内存这一点在目前的游戏中还是非常非…

解决Spring Gateway配置单个路由超时时间不生效的问题

之前springcloud gateway项目是的路由配置都是静态配置在项目的application.yml文件中&#xff0c;不能实现路由的热更新。前期业务发展也比较缓慢&#xff0c;新增路由的场景频率不是很高&#xff0c;最近业务越来越广&#xff0c;新增项目频率明显升高&#xff0c;所以想着把…

第44期 | GPTSecurity周报

GPTSecurity是一个涵盖了前沿学术研究和实践经验分享的社区&#xff0c;集成了生成预训练Transformer&#xff08;GPT&#xff09;、人工智能生成内容&#xff08;AIGC&#xff09;以及大语言模型&#xff08;LLM&#xff09;等安全领域应用的知识。在这里&#xff0c;您可以找…

数据结构:Trie(前缀树/字典树)

文章目录 一、介绍Trie1.1、Trie的结点结构1.2、Trie的整体结构 二、Trie的操作2.1、Trie插入操作2.2、Trie查找操作2.3、Trie前缀匹配操作2.4、Trie删除操作 三、实战3.1、实现Trie&#xff08;前缀树&#xff09; 一、介绍Trie Trie 又称字典树、前缀树和单词查找树&#xff…

flask_restful渲染模版

渲染模版就是在 Flask_RESTful 的类视图中要返回 html 片段代码&#xff0c;或 者是整个html 文件代码。 如何需要浏览器渲染模板内容应该使用 api.representation 这个装饰器来定 义一个函数&#xff0c; 在这个函数中&#xff0c;应该对 html 代码进行一个封装&#xff…
最新文章