7月25日JavaSE学习笔记

线程的生命周期中,等待是主动的,阻塞是被动的

锁对象

创建锁对象,锁对象同一时间只允许一个线程进入

    //创建锁对象Lock lock=new ReentrantLock(true);//创建可重入锁

可重入锁:在嵌套代码块中,锁对象一样就可以直接进入执行

公平锁:保证线程获取锁的顺序与线程请求锁的顺序一致,即按照先来先服务的原则。

非公平锁:线程获取锁的顺序与线程请求锁的顺序无关,允许插队操作。

默认情况下的锁都是非公平锁,传入一个参数为true即为公平锁


加锁 lock

解锁 unlock

有加锁就要有解锁,否则会造成死锁

尝试加锁 tryLock

尝试加锁,如果加锁成功会返回true,失败返回false

    public void method(){//lock.lock();//加锁if (lock.tryLock()){//尝试加锁:加锁成功返回true,失败falseSystem.out.println(Thread.currentThread().getName()+"加锁成功");System.out.println(Thread.currentThread().getName()+"进入方法");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(Thread.currentThread().getName()+"结束方法");lock.unlock();//解锁,忘记会发生死锁状态}else {System.out.println(Thread.currentThread().getName()+"加锁未成功");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}method();}

死锁(Deadlock)指的是在多线程编程中,两个或多个线程互相持有对方所需的资源,并且由于无法获得所需的资源而陷入无限等待的状态,导致程序无法继续执行下去。

发生死锁的必要条件有四个,分别是:

  1. 互斥条件(Mutual Exclusion):至少有一个资源每次只能被一个线程占用。

  2. 请求与保持条件(Hold and Wait):线程在持有资源的同时还可以请求其他资源。

  3. 不剥夺条件(No Preemption):线程不能被强制剥夺已经获得的资源,只能在自愿释放资源后才能由其他线程获取。

  4. 循环等待条件(Circular Wait):存在一种等待循环,即线程1等待线程2持有的资源,线程2等待线程3持有的资源,...,线程N等待线程1持有的资源。

当以上四个条件同时满足时,就可能发生死锁。一旦发生死锁,线程无法继续执行下去,程序会陷入无法解开的僵局,需要通过外部干预来解决。

为了避免死锁的发生,可以采取以下措施:

  1. 破坏互斥条件:例如,对于某些资源可以采用共享的方式,允许多个线程同时访问

  2. 破坏请求与保持条件:一次性申请所有需要的资源,而不是一个一个地申请。

  3. 破坏不剥夺条件:允许线程在持有资源的同时,根据需要剥夺其他线程的资源

  4. 破坏循环等待条件:通过定义资源的顺序,要求线程按照顺序申请资源,避免循环等待的发生。

以上措施可以在设计和实现多线程程序时考虑,来减少死锁的概率和影响。此外,通过合理的资源管理和使用,以及良好的编码规范,也可以减少死锁的发生。


ReentrantReadWriteLock

public static ReentrantReadWriteLock rrwl=new ReentrantReadWriteLock();

ReentrantReadWriteLock不是一个锁,是一个锁容器,里面有一个读锁(共享锁)和一个写锁(独占锁);原本有读锁时可以再加一个读锁,但写锁只能在没有任何线程占用时才能添加。

读锁 readLock

读锁常用于读多写少的场景,例如缓存系统、数据库查询等。多个线程可以同时获取读锁,同时读取共享资源,互不干扰。这样可以提高并发性和读取的效率。

    public int get(int index){Lock readLock = rwLock.readLock();readLock.lock();System.out.println(Thread.currentThread().getName()+"运行Get开始");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}if(index >= size){throw new IndexOutOfBoundsException("index is"+index);}System.out.println(Thread.currentThread().getName()+"运行Get结束");readLock.unlock();return values[index];}
写锁 writeLock

写锁常用于写多读少的场景,例如数据更新、写入操作等。在写锁加锁期间,其他线程无法获取读锁或写锁,确保了对共享资源的一致性和完整性。写锁是排他的,只允许一个线程进行写入操作。

    public boolean add(int item){Lock writeLock = rwLock.writeLock();writeLock.lock();System.out.println(Thread.currentThread().getName()+"运行Add开始");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}if(size>values.length-1){return false;}values[size++]=item;System.out.println(Thread.currentThread().getName()+"运行Add结束");writeLock.unlock();return true;}

线程通讯

线程通讯通过锁对象实现

如何的对象都可以是锁对象,锁对象的方法在Object类中定义,但只有对象是锁对象的时候才能调用锁对象的方法,否则会报状态异常。

wait 等待

让执行到该行代码的线程进入等待状态(等待池)

notify 唤醒

唤醒一条被该锁对象wait的线程

当多个线程调用了wait方法进入等待状态时,一个线程调用notify方法会随机唤醒其中一个等待中的线程。也就是说,调用notify方法会唤醒一个线程,但是不确定唤醒的是哪个线程。

notifyAll 唤醒所有

唤醒所有被该锁对象wait的线程

    public static final Object OBJECT=new Object();public static void method(){System.out.println(Thread.currentThread().getName()+"进入方法");synchronized (OBJECT){//指定锁对象OBJECT.notify();//唤醒一条被该锁对象wait的线程//OBJECT.notifyAll();//唤醒全部被该锁对象wait的线程System.out.println(Thread.currentThread().getName()+"进入同步代码块");try {try {System.out.println(Thread.currentThread().getName()+"进入等待状态");OBJECT.wait();//让执行到该行代码的线程进入等待状态(等待池)//结束等待状态即进入就绪状态System.out.println(Thread.currentThread().getName()+"重新运行");} catch (InterruptedException e) {e.printStackTrace();}Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(Thread.currentThread().getName()+"结束同步代码块");OBJECT.notify();}}

wait和sleep的区别?

wait是Object类中定义的方法,可以由锁对象调用,让执行到该行代码的线程进入到等待状态;

sleep是Thread类中定义的静态方法,可以让执行到该行代码的线程进入到等待状态

区别:1.sleep需要传入一个毫秒数,达到时间后会自动唤醒

              wait不能自动唤醒,必须调用notify或notifyAll方法唤醒

           2.sleep方法保持锁状态进入等待状态

              wait方法会解除锁状态,其他线程可以进入运行

当一个线程调用sleep方法时,它会暂停执行一段时间,但是它不会释放锁。换句话说,其他线程仍然无法进入该代码块,因为锁状态被保持。

而当一个线程调用wait方法时,它会释放锁,并进入等待状态。其他线程可以获取该锁并执行相应的代码块。当wait方法的线程被唤醒后,它会重新尝试获取锁,并继续执行代码。


线程池 Executors

完成线程的创建、管理和销毁工作

线程池是一种管理和维护线程的机制,它可以在应用程序中预先创建一组可重复使用的线程,并在需要时分配这些线程来执行任务。

线程池的主要作用是优化线程的创建和销毁开销,提高线程的重用率和执行效率。通过线程池,可以将任务提交给线程池,线程池会自动管理线程的生命周期,使得线程可以被重复利用,避免频繁地创建和销毁线程的开销。

创建线程池对象

线程池ThreadPoolExecutor的构造方法有7个参数依次是:

int corePoolSize                   1.核心线程数
int maximumPoolSize                2.最大线程数
long keepAliveTime                 3.持续存活时间
TimeUnit unit                      4.时间单位
BlockingQueue<Runnable> workQueue  5.任务队列
ThreadFactory threadFactory        6.线程工厂(用于创建线程)
RejectedExecutionHandler handler   7.拒绝执行的处理器(回绝策略)
        ArrayBlockingQueue qu = new ArrayBlockingQueue(12);//创建线程池对象ThreadPoolExecutor tpe=new ThreadPoolExecutor(5, 10, 10, TimeUnit.SECONDS, qu, Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());

实现Runnable接口或者Callable接口都可以作为线程任务执行

 execute 方法 执行 :

Runnable的线程任务交给线程池执行

        Runnable run =EasyExecutors::method;//交给线程池执行tpe.execute(run);

 submit 方法 提交:

将实现Runnable接口或Callable接口的线程任务提交给线程池执行

        Callable<String> call = EasyExecutors::methodCall;Future<String> f = tpe.submit(call);//提交//tpe.submit(run);

shutdown 方法 关闭:

        //关闭线程池tpe.shutdown();//结束,销毁

Callable接口

Callable接口定义了一个单一的方法call(),该方法在执行任务时可以返回结果。与Runnable的run()方法不同,call()方法可以返回一个泛型类型的结果,也可以抛出一个Exception。在执行Callable任务时,可以通过Future对象来接收任务的返回结果。

Future

Future类是用来表示异步计算结果的,它提供了一系列的方法来获取、取消和监控异步任务的执行状态,使得多线程编程更加方便和灵活。

get 方法 获取 :会等待线程执行完毕

cancel 方法 取消 :

对于正在执行中的任务,cancel方法的mayInterruptIfRunning参数可设为true,这样可通过中断执行线程来中断任务通过其他途径来中断Executor内的线程是不允许的,因为你不知道该线程正在执行哪个任务;而Future对象是Executor创建的,它会与Executor线程池互相配合来实现其任务中断策略。

        Callable<String> call = EasyExecutors::methodCall;Future<String> f = tpe.submit(call);//提交System.out.println(f.get());//会等待线程执行完毕f.cancel(true);//取消任务执行


线程池的4种回绝策略

1. AbortPolicy (默认)放弃该任务并会抛出一个异常RejectedExecutionException

2. CallerRunsPolicy 调用者执行,让传递任务的线程执行此任务

3. DiscardOldestPolicy 放弃队列中最早提交的任务,不会抛出异常

4. DiscardPolicy 直接放弃新的任务,不会抛出异常


线程池的工作原理:

        任务放置在工作队列中

1. 先检查池中是否有空闲的线程,如果有就让该线程执行任务

2. 如果没有空闲的线程,判断池中的线程数量有没有达到核心线程数:

        没有达到核心线程数,创建新的线程执行任务,直到填满核心线程数;

        如果已经达到,优先在队列中存储,直到队列填满

3. 工作队列填满后,再添加新的任务,看是否达到最大线程数:

        如果没有,创建新的线程执行任务,直到填满最大线程数;

        已经填满最大线程数,队列也已经填满,没有空闲线程,就执行回绝策略

4. 线程池中的线程达到(超过)核心线程数,超出的数量在空闲时会根据存活时间进行销毁

        直到数量达到核心线程数,如果线程的数量少于核心线程数,不会消亡


Java中内置的线程池:

        //Java中内置的线程池//可以根据工作任务来创建线程,如果没有空闲的线程就创建新的线程  线程存活时间60sExecutors.newCachedThreadPool();//设定最大线程数量的线程池Executors.newFixedThreadPool(10);//提供定时运行的处理方案Executors.newScheduledThreadPool(10);//创建一个具有单个线程的线程池,保障任务队列完全按照顺序执行Executors.newSingleThreadExecutor();

在高并发高任务情况下,核心线程数怎么设置合适?

取决于以下几个因素:

  1. 系统资源:核心线程数应根据系统的处理能力来确定。如果系统的CPU、内存等资源充足,可以适当增加核心线程数来提高并发处理能力。

  2. 任务类型:不同类型的任务对线程的需求不同。如果任务是CPU密集型,即需要大量的计算资源,那么线程数可以设置得较少,以避免线程过多而导致资源竞争。如果任务是IO密集型,即需要等待IO操作的完成,那么线程数可以设置得较多,以充分利用CPU资源。

  3. 响应时间:线程池的核心目标是提供快速响应的服务。核心线程数的设置应能够确保任务能够在合理的时间内得到处理,而不是等待线程的创建和启动。

  4. 可用线程数:线程池的总线程数应根据系统的可用线程数来设置。可用线程数是指除了线程池的核心线程数之外,系统还能够分配给线程池的最大线程数。一般情况下,可用线程数可以设置为核心线程数的两倍或更多。

综合考虑以上因素,合适的核心线程数设置可以先根据系统资源和任务类型进行初步估算,然后进行性能测试和调优,根据实际情况进行调整。


枚举类

枚举类是一种特殊的类,它定义了一组常量作为其实例,并提供了一些功能扩展。

在Java中,我们可以使用关键字"enum"来定义枚举类。枚举类的实例通常用于表示一组相关的常量,例如颜色、星期几、季节等。

需要注意的是,枚举类的实例是唯一的,可以通过调用枚举常量的名称进行比较。例如,使用day == Day.MONDAY来比较两个枚举常量是否相等。

关键字 enum 来创建枚举类枚举类首行必须枚举所有实例

枚举类默认继承Enum,但不能写继承自Enum;

是可比较的:根据实例声明的顺序

枚举类是不可序列化的,也不能克隆

public enum EasyColor {RED,YELLOW,GREEN,BLUE,PINK;public void printColor(){System.out.println(this.name());System.out.println(this.ordinal());}
}
class Test{public static void main(String[] args) {EasyColor.GREEN.printColor();}
}

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

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

相关文章

进销存系统开发,进销存源码解析,添加商品选择商品

点击添加商品信息&#xff08;可以&#xff09; (关键字范围&#xff1a;商品名称&#xff0c;简拼&#xff0c;条形码&#xff0c;SKU,规格&#xff0c;参数&#xff0c;尺寸&#xff0c;接口&#xff0c;CPU,品牌) function cwpd_selSaleGoodsNewMore_Vtax2024(domid,width…

sed利用脚本处理文件

一、sed是什么 sed 命令是利用脚本来处理文本文件。它可以依照脚本的指令来处理、编辑文本文件。主要用来自动编 辑一个或多个文件、简化对文件的反复操作、编写转换程序等。 二、sed的原理 读入新的一行内容到缓存空间&#xff1b; 从指定的操作指令中取出第一条指令&…

【时时三省】(C语言基础)分支语句2

山不在高&#xff0c;有仙则名。水不在深&#xff0c;有龙则灵。 ——csdn时时三省 多分支语句 if&#xff08;表达式1&#xff09; 语句1; else if&#xff08;表达式2&#xff09; 语句2; else 语句3; 如果表达式1成立语句1会执行 如果不成立表达式2执行 如果表达式2成…

【运维笔记】数据库无法启动,数据库炸后备份恢复数据

事情起因 在做docker作业的时候&#xff0c;把卷映射到了宿主机原来的mysql数据库目录上&#xff0c;宿主机原来的mysql版本为8.0&#xff0c;docker容器版本为5.6&#xff0c;导致翻车。 具体操作 备份目录 将/var/lib/mysql备份到~/mysql_backup&#xff1a;cp /var/lib/…

Multiview LM-ICP 配准算法

Multiview LM-ICP 配准算法针对一些大型的物体&#xff08;比如建筑物&#xff09;或者需要精细化建模的物体&#xff08;比如某个文物&#xff09;&#xff0c;仅仅进行成对的配准难以还原物体的全貌和细节。所以&#xff0c;多个视角的配准十分关键。 多视角的配准存在以下两…

[STM32]FlyMcu同时烧写BootLoader和APP文件-HEX文件组成

目录 一、前言 二、HEX文件的格式 三、组合HEX文件 四、使用FlyMcu烧录 一、前言 如题&#xff0c;BootLoader每次烧写都是全部擦除&#xff0c;当我们烧写APP程序的时候&#xff0c;BootLoader程序将不复存在&#xff0c;很多开发者或许只有USB转TTL模块&#xff0c;没有其…

grep命令搜索部分命令

首先 然后可以输入&#xff5c;以及grep命令 比如 bjobs| grep "3075*"bjobs| grep "3075"这个结果是这样的&#xff0c;

MYSQL 第四次作业

任务要求&#xff1a; 具体操作&#xff1a; 新建数据库&#xff1a; mysql> CREATE DATABASE mydb15_indexstu; Query OK, 1 row affected (0.01 sec) mysql> USE mydb15_indexstu; Database changed 新建表&#xff1a; mysql> CREATE TABLE student( ->…

遇到总条数count(*)返回不了数据

文章目录 前提1.准备数据1.1 建表语句1.2 插入数据 2.程序代码3.返回结果与分析4.验证 前提 获取h_user表中count(*)字段的值打印出来&#xff0c;打印出来是0&#xff0c;数据库中执行sql返回不是0。端点调试找到原因。下面先把数据库表数据及程序贴出来。 1.准备数据 1.1 …

CSS技巧专栏:一日一例 12 -纯CSS实现边框上下交错的按钮特效

CSS技巧专栏&#xff1a;一日一例 12 -纯CSS实现边框上下交错的按钮特效 大家好&#xff0c;今天我们来做一个上下边框交错闪动的按钮特效。 本例图片 案例分析 虽说这按钮给人的感觉就是上下两个边框交错变换了位置&#xff0c;但我们都知道border是没法移动的。那么这个按…

【无标KaiwuDB CTO 魏可伟:差异化创新,面向行业的多模架构题】

2024年7月16日&#xff0c;KaiwuDB CTO 魏可伟受邀于 2024 可信数据库发展大会主论坛发表演讲《多模一库 —— KaiwuDB 的现代数据库架构探索》&#xff0c;以下是演讲精华实录。 多模数据库 是顺应时代发展与融合趋势的产物 数据模型最早始于网状模型和层次模型&#xff0c;…

Spark实时(五):InputSource数据源案例演示

文章目录 InputSource数据源案例演示 一、​​​​​​​File Source 1、读取text文件 2、读取csv文件 3、读取json文件 二、Socket Source 三、Rate Source InputSource数据源案例演示 在Spark2.0版本之后&#xff0c;DataFrame和Dataset可以表示静态有边界的数据&am…

移动式气象站:便携科技的天气守望者

在科技日新月异的今天&#xff0c;我们身边的许多设备都在向着更加智能化、便携化的方向发展。而在气象观测领域&#xff0c;移动式气象站的出现&#xff0c;不仅改变了传统气象观测的固有模式&#xff0c;更以其灵活性和实时性&#xff0c;在气象监测、灾害预警等领域发挥着越…

MySQL练习05

题目 步骤 触发器 use mydb16_trigger; #使用数据库create table goods( gid char(8) primary key, name varchar(10), price decimal(8,2), num int);create table orders( oid int primary key auto_increment, gid char(10) not null, name varchar(10), price decima…

基于python的BP神经网络红酒品质分类预测模型

1 导入必要的库 import pandas as pd import numpy as np import matplotlib.pyplot as plt from sklearn.model_selection import train_test_split from sklearn.preprocessing import LabelEncoder from tensorflow.keras.models import Sequential from tenso…

NET8部署Kestrel服务HTTPS深入解读TLS协议之Certificate证书

Certificate证书 Certificate称为数字证书。数字证书是一种证明身份的电子凭证&#xff0c;它包含一个公钥和一些身份信息&#xff0c;用于验证数字签名和加密通信。数字证书在网络通信、电子签名、认证授权等场景中都有广泛应用。其特征如下&#xff1a; 由权威机构颁发&…

跟李沐学AI:池化层

目录 二维最大池化 填充、步幅和多个通道 平均池化层 池化层总结 二维最大池化 返回滑动窗口中的最大值。 图为池化窗口形状为 22 的最大池化层。着色部分是第一个输出元素&#xff0c;以及用于计算这个输出的输入元素: max(0,1,3,4)4。池化层与卷积层类似&#xff0c;不断…

单元测试的最佳实践

整体架构 合适的架构可以提升可测试性。比如菱形对称架构的模块化和解耦特性使得系统各个部分可以独立进行单元测试。这不仅提高了测试的效率&#xff0c;还能够减少测试的依赖性&#xff0c;提高测试准确性。 代码设计 代码设计和可测试性有密切关联。强烈建议一个方法的代码行…

Android 15 适配整理——实践版

背景 谷歌发布Android 15后&#xff0c;国内的手机厂商迅速行动&#xff0c;开始了新系统的适配工作。小米、OPPO、vivo和联想等金标联盟成员联合发布了适配公告&#xff0c;督促APP开发者在2024年8月31日前完成适配工作&#xff0c;否则将面临搜索标签提示、应用降级、分机型…

JavaWeb笔记_JSTL标签库JavaEE三层架构案例

一.JSTL标签库 1.1 JSTL概述 JSTL(jsp standard tag library):JSP标准标签库,它是针对EL表达式一个扩展,通过JSTL标签库与EL表达式结合可以完成更强大的功能 JSTL它是一种标签语言,JSTL不是JSP内置标签 JSTL标签库主要包含: ****核心标签 格式化标签 …