多线程学习Day07

共享模型之不可变

从一个日期转换的问题开始

@Slf4j(topic = "c.Test1")
public class Test1 {public static void main(String[] args) {SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");for (int i = 0; i < 10; i++) {new Thread(() -> {try {log.debug("{}", sdf.parse("1951-04-21"));} catch (Exception e) {log.error("{}", e);}}).start();}}
}

这里出现了异常

java.lang.NumberFormatException: For input string: "4E14"at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)at java.base/java.lang.Long.parseLong(Long.java:692)at java.base/java.lang.Long.parseLong(Long.java:817)at java.base/java.text.DigitList.getLong(DigitList.java:195)at java.base/java.text.DecimalFormat.parse(DecimalFormat.java:2121)at java.base/java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1933)at java.base/java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1541)at java.base/java.text.DateFormat.parse(DateFormat.java:393)at n7.Test1.lambda$main$0(Test1.java:14)at java.base/java.lang.Thread.run(Thread.java:829)

加锁当然能解决这个问题

 synchronized (sdf){try {log.debug("{}", sdf.parse("1951-04-21"));} catch (Exception e) {log.error("{}", e);}}

换一个不可变类

@Slf4j(topic = "c.Test1")
public class Test1 {public static void main(String[] args) {DateTimeFormatter stf = DateTimeFormatter.ofPattern("yyyy-MM-dd");for (int i = 0; i < 10; i++) {new Thread(() -> {TemporalAccessor parse = stf.parse("1951-04-21");log.debug("{}",parse);}).start();}}
}

不可变类的设计

public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
/** Cache the hash code for the string */
private int hash; // Default to 0
// ...
}
北

比如String这个类,他的两个成员变量,一个value[]使用final修饰,一个hash是私有的并且没有get方法,类也加上了fianl修饰,防止子类对其有影响,属性用 final 修饰保证了该属性是只读的,不能修改,类用 final 修饰保证了该类中的方法不能被覆盖,防止子类无意间破坏不可变性


保护性拷贝

public String substring(int beginIndex) {
if (beginIndex < 0) {
throw new StringIndexOutOfBoundsException(beginIndex);
}
int subLen = value.length - beginIndex;
if (subLen < 0) {
throw new StringIndexOutOfBoundsException(subLen);
}
return (beginIndex == 0) ? this : new String(value, beginIndex, subLen);
}

发现其内部是调用 String 的构造方法创建了一个新字符串,再进入这个构造看看,是否对 final char[] value 做出了修改:

public String(char value[], int offset, int count) {
if (offset < 0) {
throw new StringIndexOutOfBoundsException(offset);
}
if (count <= 0) {
if (count < 0) {
throw new StringIndexOutOfBoundsException(count);
}
if (offset <= value.length) {
this.value = "".value;
return;
}
}
if (offset > value.length - count) {
throw new StringIndexOutOfBoundsException(offset + count);
}
this.value = Arrays.copyOfRange(value, offset, offset+count);
}

享元模式

 定义 英文名称:Flyweight pattern. 当需要重用数量有限的同一类对象时

在JDK中 Boolean,Byte,Short,Integer,Long,Character 等包装类提供了 valueOf 方法,例如 Long 的valueOf 会缓存 -128~127 之间的 Long 对象,在这个范围之间会重用对象,大于这个范围,才会新建 Long 对象:

public static Long valueOf(long l) {
final int offset = 128;
if (l >= -128 && l <= 127) { // will cache
return LongCache.cache[(int)l + offset];
}
return new Long(l);
}

Byte, Short, Long 缓存的范围都是 -128~127
Character 缓存的范围是 0~127
Integer的默认范围是 -128~127
             最小值不能变
             但最大值可以通过调整虚拟机参数 `
             -Djava.lang.Integer.IntegerCache.high` 来改变
Boolean 缓存了 TRUE 和 FALSE

例如:一个线上商城应用,QPS 达到数千,如果每次都重新创建和关闭数据库连接,性能会受到极大影响。 这时预先创建好一批连接,放入连接池。一次请求到达后,从连接池获取连接,使用完毕后再还回连接池,这样既节约了连接的创建和关闭时间,也实现了连接的重用,不至于让庞大的连接数压垮数据库。

一个小的连接池例子:

public class Test2 {public static void main(String[] args) {Pool  pool=new Pool(2);for (int i=0;i<5;i++){new Thread(()->{Connection conn=pool.borrow();try {Thread.sleep(new Random().nextInt(1000));} catch (InterruptedException e) {throw new RuntimeException(e);}pool.free(conn);}).start();}}
}
@Slf4j(topic = "c.Pool")
class Pool{//1.连接池大小private final int poolSize;//2.连接对象数组private Connection[] connections;//3.连接状态数组,0表示空闲,1表示繁忙private AtomicIntegerArray states;//4.构造方法public Pool(int poolSize){this.poolSize=poolSize;this.connections=new Connection[poolSize];this.states=new AtomicIntegerArray(new int[poolSize]);for(int i=0;i<poolSize;i++){connections[i]=new MockConnection("连接"+i);}}//借连接public Connection borrow()  {while (true){for (int i=0;i<poolSize;i++){if(states.get(i)==0){log.debug("成功进入");if(states.compareAndSet(i,0,1)){log.debug("borrow{}",connections[i]);return connections[i];}}}//没有空闲连接进入等待synchronized (this){try {log.debug("wait...");this.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}}}}//归还连接public void free(Connection conn){for (int i=0;i<poolSize;i++){if(connections[i]==conn){states.set(i,0);log.debug("free{}",conn);synchronized (this){this.notifyAll();}break;}}}
}

final原理

设置 final 变量的原理
public class TestFinal {
final int a = 20;
}

字节码 

0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: bipush 20
7: putfield #2 // Field a:I
<-- 写屏障
10: return
获取final变量的原理
1. 编译时的行为
  • 编译期常量:如果一个final变量在声明时就被显式初始化(例如,基本类型或字符串字面量),并且它是静态的(static),那么它会被视为编译期常量。Java编译器会将这些常量的值嵌入到任何使用它们的代码中。这意味着,如果这些final常量的值在编译时是已知的,则它们的使用可以在编译时被直接替换为实际的值。

  • 非编译期常量:对于非静态的final变量,或者其值在运行时才能确定的final变量(例如,通过方法计算得到的值),则它们不是编译期常量。这些变量的值存储在类的实例中(非静态)或类本身(静态但非常量)。

2. 运行时的行为
  • 内存模型和可见性final字段的最大特点之一在于它们对内存模型的影响。在Java内存模型中,正确构造的对象(在对象的构造函数完成后,final字段的值就不再改变)中的final字段,可以保证被不同线程安全地读取,无需额外的同步措施。这种行为是通过在构造器结束时对final字段的写入,以及每次读取final字段时都建立的“初始化安全性”保证来实现的。

  • 构造器内的赋值:Java允许在构造器内部对final变量进行赋值。一旦构造器完成,final变量的值就固定下来,任何尝试修改final变量的操作都将导致编译错误。

共享模型之工具

线程池

自定义线程池

终于成功了

@Slf4j(topic = "c.Test1")
public class Test1 {public static void main(String[] args) {ThreadPool threadPool= new ThreadPool(2,1000,TimeUnit.MILLISECONDS,10);for (int i=0;i<5;i++){int j=i;threadPool.excute(()->{log.debug("{}",j);});}}
}
@Slf4j(topic = "c.ThreadPool")
class ThreadPool{//任务队列private BlockingQueue<Runnable> taskQueue;//线程集合private HashSet<Worker> workers=new HashSet();//核心线程数private int coreSize;//获取任务的超时时间private long timeout;private TimeUnit timeUnit;//执行任务public void excute(Runnable task){//当任务数没有超过coreSize时,交给worker对象执行,如果超过了,加入任务队列暂存synchronized (workers){if(workers.size()<coreSize){Worker worker=new Worker(task);log.debug("新增worker {},{}",worker,task);workers.add(worker);worker.start();}else {log.debug("加入任务队列 {}",task);taskQueue.put(task);}}}public ThreadPool(int coreSize, long timeout, TimeUnit timeUnit,int queueCapCIty) {this.coreSize = coreSize;this.timeout = timeout;this.timeUnit = timeUnit;this.taskQueue=new BlockingQueue<>(queueCapCIty);}class Worker extends Thread{private Runnable task;public Worker( Runnable task) {this.task = task;}@Overridepublic void run(){//执行任务1.当task不为空,直接执行任务2.当task执行完毕,接着从任务队列获取任务并执行while (task!=null||(task=taskQueue.take())!=null){try {log.debug("正在执行...{}",task);task.run();}catch (Exception e){e.printStackTrace();}finally {task=null;}}synchronized (workers){log.debug("worker被移除{}",this);workers.remove(this);}}}
}class BlockingQueue<T>{//1.任务队列private Deque<T> queue=new ArrayDeque<>();//2.锁private ReentrantLock lock=new ReentrantLock();//3.生产者条件变量private Condition fullWaitSet=lock.newCondition();//4.消费者条件变量private Condition emptyWaitSet=lock.newCondition();//5.容量private int capcity;public BlockingQueue(int capacity) {this.capcity=capacity;}//带超时的阻塞获取public T poll(long timeout, TimeUnit unit){lock.lock();try {//将超时时间转化为纳秒long nanos=unit.toNanos(timeout);while (queue.isEmpty()){try {//返回的是剩余时间if(nanos<=0){return null;}nanos= emptyWaitSet.awaitNanos(nanos);} catch (InterruptedException e) {throw new RuntimeException(e);}}T t=queue.removeFirst();fullWaitSet.signal();return t;}finally {lock.unlock();}}//阻塞获取public T take(){lock.lock();try {while (queue.isEmpty()){try {emptyWaitSet.await();} catch (InterruptedException e) {throw new RuntimeException(e);}}T t=queue.removeFirst();fullWaitSet.signal();return t;}finally {lock.unlock();}}//阻塞添加public void put(T element){lock.lock();try {while (queue.size()==capcity){try {fullWaitSet.await();} catch (InterruptedException e) {throw new RuntimeException(e);}}queue.addLast(element);//放完了之后唤醒一下等着队列元素的线程emptyWaitSet.signal();}finally {lock.unlock();}}//获取大小public int size(){lock.lock();try {return capcity;}finally {lock.unlock();}}
}
17:16:48 [main] c.ThreadPool - 新增worker Thread[Thread-0,5,main],n8.Test1$$Lambda$30/0x00000008000d5440@77167fb7
17:16:48 [main] c.ThreadPool - 新增worker Thread[Thread-1,5,main],n8.Test1$$Lambda$30/0x00000008000d5440@3c9d0b9d
17:16:48 [main] c.ThreadPool - 加入任务队列 n8.Test1$$Lambda$30/0x00000008000d5440@2f112965
17:16:48 [Thread-0] c.ThreadPool - 正在执行...n8.Test1$$Lambda$30/0x00000008000d5440@77167fb7
17:16:48 [main] c.ThreadPool - 加入任务队列 n8.Test1$$Lambda$30/0x00000008000d5440@1a04f701
17:16:48 [main] c.ThreadPool - 加入任务队列 n8.Test1$$Lambda$30/0x00000008000d5440@4e91d63f
17:16:48 [Thread-1] c.ThreadPool - 正在执行...n8.Test1$$Lambda$30/0x00000008000d5440@3c9d0b9d
17:16:48 [Thread-0] c.Test1 - 0
17:16:48 [Thread-1] c.Test1 - 1
17:16:48 [Thread-1] c.ThreadPool - 正在执行...n8.Test1$$Lambda$30/0x00000008000d5440@1a04f701
17:16:48 [Thread-0] c.ThreadPool - 正在执行...n8.Test1$$Lambda$30/0x00000008000d5440@2f112965
17:16:48 [Thread-1] c.Test1 - 3
17:16:48 [Thread-0] c.Test1 - 2
17:16:48 [Thread-1] c.ThreadPool - 正在执行...n8.Test1$$Lambda$30/0x00000008000d5440@4e91d63f
17:16:48 [Thread-1] c.Test1 - 4

下面这个加了拒绝策略

@Slf4j(topic = "c.Test1")
public class Test1 {public static void main(String[] args) {ThreadPool threadPool= new ThreadPool(1,1000,TimeUnit.MILLISECONDS,1,(queue,task)->{//1.死等//queue.put(task);//2.带超时等待//queue.offer(task,500,TimeUnit.MILLISECONDS);//3.让调用者放弃执行//log.debug("放弃",task);//4.抛出异常//throw new RuntimeException("任务执行失败"+task);//5.让调用者自己执行任务task.run();});for (int i=0;i<3;i++){int j=i;threadPool.excute(()->{try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}log.debug("{}",j);});}}
}
@FunctionalInterface//拒绝策略
interface RejectPolicy<T>{void reject(BlockingQueue queue,T task);
}
@Slf4j(topic = "c.ThreadPool")
class ThreadPool{//任务队列private BlockingQueue<Runnable> taskQueue;//线程集合private HashSet<Worker> workers=new HashSet();//核心线程数private int coreSize;//获取任务的超时时间private long timeout;private TimeUnit timeUnit;private RejectPolicy<Runnable>rejectPolicy;//执行任务public void excute(Runnable task){//当任务数没有超过coreSize时,交给worker对象执行,如果超过了,加入任务队列暂存synchronized (workers){if(workers.size()<coreSize){Worker worker=new Worker(task);log.debug("新增worker {},{}",worker,task);workers.add(worker);worker.start();}else {log.debug("加入任务队列 {}",task);taskQueue.put(task);/** 1.死等* 2..带超时等待* 3.放弃执行* 4.抛出异常* */taskQueue.tryPut(rejectPolicy,task);}}}public ThreadPool(int coreSize, long timeout, TimeUnit timeUnit,int queueCapCIty,RejectPolicy<Runnable> rejectPolicy) {this.coreSize = coreSize;this.timeout = timeout;this.timeUnit = timeUnit;this.taskQueue=new BlockingQueue<>(queueCapCIty);this.rejectPolicy=rejectPolicy;}class Worker extends Thread{private Runnable task;public Worker( Runnable task) {this.task = task;}@Overridepublic void run(){//执行任务1.当task不为空,直接执行任务2.当task执行完毕,接着从任务队列获取任务并执行while (task!=null||(task=taskQueue.poll(timeout,timeUnit))!=null){try {log.debug("正在执行...{}",task);task.run();}catch (Exception e){e.printStackTrace();}finally {task=null;}}synchronized (workers){log.debug("worker被移除{}",this);workers.remove(this);}}}
}
@Slf4j(topic = "c.BlockingQueue")
class BlockingQueue<T>{//1.任务队列private Deque<T> queue=new ArrayDeque<>();//2.锁private ReentrantLock lock=new ReentrantLock();//3.生产者条件变量private Condition fullWaitSet=lock.newCondition();//4.消费者条件变量private Condition emptyWaitSet=lock.newCondition();//5.容量private int capcity;public BlockingQueue(int capacity) {this.capcity=capacity;}//带超时的阻塞获取public T poll(long timeout, TimeUnit unit){lock.lock();try {//将超时时间转化为纳秒long nanos=unit.toNanos(timeout);while (queue.isEmpty()){try {//返回的是剩余时间if(nanos<=0){return null;}nanos= emptyWaitSet.awaitNanos(nanos);} catch (InterruptedException e) {throw new RuntimeException(e);}}T t=queue.removeFirst();fullWaitSet.signal();return t;}finally {lock.unlock();}}//阻塞获取public T take(){lock.lock();try {while (queue.isEmpty()){try {emptyWaitSet.await();} catch (InterruptedException e) {throw new RuntimeException(e);}}T t=queue.removeFirst();fullWaitSet.signal();return t;}finally {lock.unlock();}}//阻塞添加public void put(T element){lock.lock();try {while (queue.size()==capcity){try {log.debug("等待加入任务队列{}...",element);fullWaitSet.await();} catch (InterruptedException e) {throw new RuntimeException(e);}}log.debug("加入任务队列{}",element);queue.addLast(element);//放完了之后唤醒一下等着队列元素的线程emptyWaitSet.signal();}finally {lock.unlock();}}//带超时时间的阻塞添加public boolean offer(T task,long timeout,TimeUnit timeUnit){lock.lock();try {long nanos=timeUnit.toNanos(timeout);while (queue.size()==capcity){try {log.debug("等待加入任务队列{}...",task);if(nanos<=0){return false;}nanos= fullWaitSet.awaitNanos(nanos);} catch (InterruptedException e) {throw new RuntimeException(e);}}log.debug("加入任务队列{}",task);queue.addLast(task);//放完了之后唤醒一下等着队列元素的线程emptyWaitSet.signal();return true;}finally {lock.unlock();}}//获取大小public int size(){lock.lock();try {return capcity;}finally {lock.unlock();}}public void tryPut(RejectPolicy<T> rejectPolicy,T task){lock.lock();try {if(queue.size()==capcity){rejectPolicy.reject(this,task);}else {log.debug("加入任务队列{}",task);queue.addLast(task);emptyWaitSet.signal();}}finally {lock.unlock();}}
}

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

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

相关文章

buuctf-misc题目练习二

ningen 打开题目后是一张图片&#xff0c;放进winhex里面 发现PK&#xff0c;PK是压缩包ZIP 文件的文件头&#xff0c;下一步是想办法进行分离 Foremost可以依据文件内的文件头和文件尾对一个文件进行分离&#xff0c;或者识别当前的文件是什么文件。比如拓展名被删除、被附加…

元素设置 flex:1,但是会被内部长单词宽度超出拉伸

初始布局如上图&#xff0c;left中是代码编辑器&#xff0c;实际上是个文本域&#xff0c;当输入长文本过长时&#xff0c;left宽度会被拉伸。 右侧容器被挤压。 解决方案&#xff1a;width&#xff1a;0&#xff1b; .left{flex:1; width:0} 当输入长文本过长时&#xff0c…

保姆级零基础微调大模型(LLaMa-Factory,多卡版)

此处非常感谢https://github.com/hiyouga/LLaMA-Factory这个项目。 看到网上的教程很多都是教如何用webui来微调的,这里出一期命令行多卡微调教程~ 1. 模型准备 模型下载比较方便的方法: 1. modelscope社区(首选,速度很高,并且很多需要申请的模型都有)注意要选择代码…

HTML4(二)

文章目录 1 开发者文档2 基本标签2.1 排版标签2.2 语义化标签2.3 行内元素与块级元素2.4 文本标签2.5 常用标签补充 3 图片标签4 超链接标签4.1 跳转页面4.2 跳转文件4.3 跳转锚点4.4 唤起指定应用 5 列表5.1 有序列表5.2 无序列表5.3 自定义列表 6 表格6.1 基本结构6.2 表格标…

【Android】Kotlin学习之数据容器(数组创建)

kotlin数组 数组是一种初始化时指定容器大小, 不可以动态调整其大小的容器 数组创建

WPF之改变任务栏图标及预览

1&#xff0c;略缩图添加略缩按钮。 <Window.TaskbarItemInfo><TaskbarItemInfo x:Name"taskInfo" ProgressState"None" ProgressValue"0.6" ><TaskbarItemInfo.ThumbButtonInfos><ThumbButtonInfo x:Name"btiPlay&q…

雷伴品鉴【神农式】倪琴 倪诗韵古琴

雷伴品鉴【神农式】倪琴 倪诗韵古琴 此琴材质为老杉木音色细腻&#xff0c;下指按弹舒适&#xff0c;手感极好漆面精美&#xff0c;线条流畅。

OpenCV4.8 VS2019 MFC编程出现的诡异现象

OpenCV4.8及OpenCV4.4 VS2019MFC编程在调用imred&#xff08;&#xff09;函数时&#xff0c;debug X64试运行没问题。 release X64试运行时出现下面错误。 void CEasyPictureDlg::OnBnClickedOpen() {CFileDialog fdlg(TRUE, NULL, 0, OFN_HIDEREADONLY | OFN_OVERWRITEPROMP…

私人健身教练预约管理小程序开发源码现成案例(小程序+APP+H5 源码部署)

一、私人健身教练预约管理系统-环境介绍 1.1 私人健身教练预约管理系统-运行环境 开发语言&#xff1a;PHP 数据库&#xff1a;MySQL 系统架构&#xff1a;TP 后端&#xff1a;SpringBoot 前端&#xff1a;Vue 2. 私人健身教练预约管理系统-系统介绍。 2.1私人健身教练预约管…

EasyExcel导出带自定义下拉框数据的Excel模板

文章目录 前言&#x1f4dd;一、导入依赖二、创建导出工具1.创建模板实体类2.创建自定义注解3.添加动态选择接口4.EasyExcelUtil工具类 三、导出、导入Excel接口1.导出接口2.导入接口3.导出结果 总结 前言&#x1f4dd; 在项目中导入excel时需要通过下拉框选择值传入&#xff…

【websocket-客户端可视化工具】

postman 新版postman (版本v11以上) &#xff0c;除了http协议&#xff0c;还支持了Websocket&#xff0c;MQTT&#xff0c;gRPC等多种连接协议&#xff0c;可以作为多种协议的客户端&#xff0c;使用起来非常方便。 使用 服务端代码 这里以websocket协议举例&#xff0c;代…

基于51单片机的八路抢答器—加随机抽选功能

基于51单片机的八路抢答器 &#xff08;仿真&#xff0b;程序原理图&#xff0b;设计报告&#xff09; 功能介绍 具体功能&#xff1a; 1.主持人按键控制开始抢答&#xff1b; 2.开始抢答按下&#xff0c;数码管20秒倒计时&#xff1b; 3.8个按键代表八位选手&#xff0c;谁…

视频降噪算法 hqdn3d 原理分析

视频降噪 视频降噪是一种处理技术&#xff0c;旨在减少视频中的噪声&#xff0c;提高画面质量。噪声可能来自多种源头&#xff0c;包括摄像机的传感器、压缩算法、传输过程中的干扰等。降噪处理对于视频监控、视频会议、电影后期制作以及任何需要高画质输出的应用场景都非常重…

今天又发现一个有意思的问题:SQL Server安装过程中下载报错,证明GPT是可以解决问题的

我们在安装数据库的时候&#xff0c;都会有报错问题&#xff0c;无论是Oracle、SQL Server、还是MySQL&#xff0c;都会遇到各种各样的报错&#xff0c;这归根到底还是因为电脑环境的不同&#xff0c;和用户安装的时候&#xff0c;操作习惯的不一样导致的问题。今天的问题是&am…

SwiftUI 5.0(iOS 17.0,macOS 14.0+)新 Inspector 辅助视图之趣味漫谈

概览 在 SwiftUI 开发中,苹果为我们提供了多种辅助视图用来显示额外信息从而极大丰富了应用的表现力,比如:Alert、Sheet、ContextMenu 等等。 从 SwiftUI 5.0(iOS 17+)开始, 又增加了一种全新的辅助视图:Inspector。 在本篇博文中,您将学到如下内容: 概览1. Inspe…

哈迪斯2发售时间 哈迪斯游戏攻略 苹果电脑怎么玩《哈迪斯2》

这两年肉鸽游戏大爆发&#xff0c;只要不是美女抽卡养成那基本上就是肉鸽了&#xff0c;但是真正让玩家口服心服的肉鸽游戏不多&#xff0c;《哈迪斯》绝对算是其中一款。 近日让玩家期待已久的肉鸽大作&#xff0c;晶体管工作室制作的《哈迪斯》正统续作《哈迪斯2》终于开卖了…

网络编程基础回顾

计算机网络&#xff08;5&#xff09;&#xff1a;运输层 OSI 模型与 TCP/IP 协议 OSI七层协议模型 (open system interconnection) 应用层&#xff1a;为应用数据提供服务表示层&#xff1a;数据格式转化&#xff0c;数据加密会话层&#xff1a;建立、维护和管理会话传输层&…

2-6 任务 猜数小游戏(单次版)

本任务要求编写一个猜数小游戏&#xff08;单次版&#xff09;&#xff0c;游戏规则是计算机产生一个0到100之间的随机整数&#xff0c;用户通过输入猜测的数字进行猜测&#xff0c;根据猜测情况给出提示&#xff0c;直到猜对为止。编程思路是利用while循环和多分支结构实现永真…

美特CRM upload.jsp 文件上传致RCE漏洞复现(CNVD-2023-06971)

0x01 产品简介 MetaCRM是一款智能平台化CRM软件,通过提升企业管理和协同办公,全面提高企业管理水平和运营效率,帮助企业实现卓越管理。美特软件开创性地在CRM领域中引入用户级产品平台MetaCRM V5/V6,多年来一直在持续地为客户创造价值,大幅提升了用户需求满足度与使用的满意…

静态分配IP,解决本地连接不上Linux虚拟机的问题

在Window环境下&#xff0c;使用远程终端工具连接不了VMware搭建的Linux虚拟机&#xff08;CentOS 7&#xff09;&#xff0c;并且在命令行ping不通该Linux虚拟机的IP地址。下面通过配置网关解决本地与Linux虚拟机连接问题&#xff1a; 1 查看虚拟机网关地址 在VMware虚拟机上…