当前位置: 首页 > news >正文

Netty学习笔记1

Netty学习笔记(一)

在的互联网环境下,分布式系统大行其道,而分布式系统的根基在于网络编程,而 Netty 恰恰是 Java 领域网络编程的王者。如果要致力于开发高性能的服务器程序、高性能的客户端程序,必须掌握 Netty。

视频链接:黑马程序员Netty全套教程,全网最全Netty深入浅出教程,Java网络编程的王者

NIO基础

non-blocking io 非阻塞IO

1、三大组件

Channel、Buffer、Selector

Channel 有一点类似于 stream,它就是读写数据的双向通道

常见的Channel有:

  • FileChannel
  • DatagramChannel
  • SocketChannel
  • ServerSocketChannel

Buffer则用来缓冲读写数据,常见的Buffer有:

  • ByteBuffer
  • ShortBuffer
  • IntBuffer
  • LongBuffer
  • FloatBuffer
  • DoubleBuffer
  • CharBuffer

服务器设计——多线程版

❗ 缺点:

  • 内存占用高
  • 线程上下文切换成本高
  • 只适合连接少的场景

服务器设计——线程池版

❗ 缺点:

  • 阻塞模式下,线程仅能处理一个socket连接
  • 仅适合短连接场景

服务器设计——Selector版

Selector的作用就是配合一个线程来管理多个channel,获取这些channel上发生的事件,这些channel工作在非阻塞模式下,不会让线程吊死在一个channel上,适合连接数特别多,但流量低的场景(low traffic)

调用selector的select()会阻塞直到channel发生了读写就绪事件,这些事件发生,select方法就会返回这些事件交给thread来处理

2、ByteBuffer

正确使用姿势:

  1. 向buffer写入数据,例如调用channel.read(buffer)
  2. 调用flip()切换至读模式
  3. 从buffer读取数据,例如调用buffer.get()
  4. 调用clear()compact()切换至写模式
  5. 重复1-4步骤
@Slf4j
public class TestByteBuffer {public static void main(String[] args) {// FileChannel// 1、输入输出流 2、RandomAccessFiletry (FileChannel channel = new FileInputStream("data.txt").getChannel()) {// 准备缓存区ByteBuffer buffer = ByteBuffer.allocate(10);while (true) {// 从channel读取数据,向buffer写入int len = channel.read(buffer);log.debug("读取到的字节数 {}", len);if (len == -1) { // 没有内容break;}// 打印buffer的内容buffer.flip(); // 切换读模式while (buffer.hasRemaining()) { // 是否还有剩余未读数据byte b = buffer.get();log.debug("读取到的字节 {}", (char) b);}// 切换写模式buffer.clear();}} catch (IOException e) {e.printStackTrace();}}
}

ByteBuffer有以下重要属性:

  • capacity
  • position
  • limit

写模式下,position是写入位置,limit等于容量

flip动作发生后,position切换为读取位置,limit切换为读取限制

常见方法:

分配空间

可以使用allocate方法为ByteBuffer分配空间

        /** class java.nio.HeapByteBuffer    java堆内存,读写效率较低,受到gc影响* class java.nio.DirectByteBuffer  直接内存,读写效率高(少一次拷贝),不受gc影响,分配效率低*/
System.out.println(ByteBuffer.allocate(16).getClass());
System.out.println(ByteBuffer.allocateDirect(16).getClass());

写入数据

  • 调用channel的read方法
  • 调用buffer自己的put方法

读取数据

  • 调用channel的write方法
  • 调用buffer自己的get方法

get方法会让position读指针向后走,如果想重复读取数据

  • 可以调用rewind方法将position重新置为0
  • 或者调用get(int i)方法获取索引i的内容,它不会移动读指针
public class TestByteBufferRead {public static void main(String[] args) {ByteBuffer buffer = ByteBuffer.allocate(16);buffer.put(new byte[]{'a', 'b', 'c', 'd'});buffer.flip();// 从头开始读buffer.get(new byte[4]);ByteBufferUtil.debugAll(buffer);buffer.rewind();System.out.println((char) buffer.get());buffer.rewind();// mark & reset// mark 做一个标记,记录position位置,reset是将position重置到mark的位置System.out.println((char) buffer.get());System.out.println((char) buffer.get());buffer.mark(); // 加标记,索引为2的位置System.out.println((char) buffer.get());System.out.println((char) buffer.get());buffer.reset(); // 将position重置到上次标记的位置System.out.println((char) buffer.get());System.out.println((char) buffer.get());// get(i) 不会改变读索引的位置System.out.println((char) buffer.get(1));ByteBufferUtil.debugAll(buffer);}
}

字符串与ByteBuffer互转

public class TestByteBufferString {public static void main(String[] args) {// 1. 字符串转为ByteBufferByteBuffer buffer = ByteBuffer.allocate(16);buffer.put("hello".getBytes());ByteBufferUtil.debugAll(buffer);// 2. CharsetByteBuffer buffer1 = StandardCharsets.UTF_8.encode("hello");ByteBufferUtil.debugAll(buffer1);// 3. wrapByteBuffer buffer2 = ByteBuffer.wrap("hello".getBytes(StandardCharsets.UTF_8));ByteBufferUtil.debugAll(buffer2);// 转为字符串String s = StandardCharsets.UTF_8.decode(buffer2).toString();System.out.println(s);buffer.flip();String s1 = StandardCharsets.UTF_8.decode(buffer).toString();System.out.println(s1);}
}

Scattering Reads

分散读取,有一个文本文件3parts.txt

public class TestScatteringReads {public static void main(String[] args) {try (FileChannel channel = new RandomAccessFile("3parts.txt", "r").getChannel()) {ByteBuffer b1 = ByteBuffer.allocate(3);ByteBuffer b2 = ByteBuffer.allocate(3);ByteBuffer b3 = ByteBuffer.allocate(5);channel.read(new ByteBuffer[]{b1, b2, b3});b1.flip();b2.flip();b3.flip();ByteBufferUtil.debugAll(b1);ByteBufferUtil.debugAll(b2);ByteBufferUtil.debugAll(b3);} catch (IOException e) {e.printStackTrace();}}
}

Gathering Writes

public class TestGatheringWrites {public static void main(String[] args) {ByteBuffer b1 = StandardCharsets.UTF_8.encode("hello");ByteBuffer b2 = StandardCharsets.UTF_8.encode("world");ByteBuffer b3 = StandardCharsets.UTF_8.encode("您好");try (FileChannel channel = new RandomAccessFile("words.txt", "rw").getChannel()) {channel.write(new ByteBuffer[]{b1, b2, b3});} catch (IOException e) {e.printStackTrace();}}
}

ByteBuffer 黏包 半包

需求:

/*
网络上有多条数据发送给服务端,数据之间使用 \n 进行分隔
但由于某种原因这些数据在接收时,被进行了重新组合,例如原始数据有3条为
Hello,world\n
I'm zhangsan\n
How are you?\n
变成了下面的两个ByteBuffer(黏包,半包)
Hello,world\nI'm zhangsan\nHo
w are you?\n
现在要求你编写程序,将错乱的数据恢复成原始的按 \n 分隔的数据
*/

具体实现:

package com.example.netty.ch1;import com.example.netty.utils.ByteBufferUtil;import java.nio.ByteBuffer;public class TestByteBufferCase {public static void main(String[] args) {ByteBuffer source = ByteBuffer.allocate(32);source.put("Hello,world\nI'm zhangsan\nHo".getBytes());split(source);source.put("w are you?\n".getBytes());split(source);}private static void split(ByteBuffer source) {source.flip();for (int i = 0; i < source.limit(); i++) {// 找到一条完整的消息if (source.get(i) == '\n') {int length = i + 1 - source.position();// 把完整消息存入新的ByteBufferByteBuffer target = ByteBuffer.allocate(length);// 从source读,向target写for (int j = 0; j < length; j++) {byte b = source.get();target.put(b);}ByteBufferUtil.debugAll(target);}}source.compact();}
}

3、文件编程

FileChannel

⚠注意

FileChannel 只能工作在阻塞模式下

获取FileChannel

  • 通过FileInputStream获取的channel只能读
  • 通过FileOuputStream获取的channel只能写
  • 通过RandomAccessFile是否能读写根据构造RandomAccessFile时的读写模式决定

读取

会从channel读取数据填充ByteBuffer,返回值表示读到了多少字节,-1表示到达了文件的末尾

int len = channel.read(buffer);

写入

ByteBuffer buffer = ...;
buffer.put(...); // 写入数据
buffer.flip(); // 切换读模式while (buffer.hasRemaining()) {channel.write(buffer);
}

关闭

channel必须关闭

channel.close();

两个Channel传输数据

public class TestFileChannelTransferTo {public static void main(String[] args) {try (FileChannel from = new FileInputStream("data.txt").getChannel();FileChannel to = new FileOutputStream("to.txt").getChannel()) {// 效率高,底层使用操作系统的零拷贝进行优化,2g 数据long size = from.size();// i 代表还剩余多少个字节for (long i = size; i > 0;) {i -= from.transferTo((size - i), i, to);}} catch (IOException exception) {exception.printStackTrace();}}
}

Path

JDK7 引入了Path和Paths类

  • Path 用来表示文件路径
  • Paths 是工具类,用来获取Path实例
Path source = Paths.get("test.txt");
Path source = Paths.get("d:\\test.txt");
Path source = Paths.get("d:/test.txt");
Path source = Paths.get("d:\\data", "test.txt");

正常化路径:path.normalize()

Files

检查文件是否存在:Files.exists(path)

创建一级目录:Files.createDirectory(path)

创建多级目录:Files.createDirectories(path)

拷贝文件:Files.copy(source, target)

移动文件:Files.move(source, target, StandardCopyOption.ATOMIC_MOVE)

删除文件:Files.delete(target)

遍历目录

public class TestFilesWalkFileTree {public static void main(String[] args) throws IOException {AtomicInteger dirCount = new AtomicInteger();AtomicInteger fileCount = new AtomicInteger();Files.walkFileTree(Paths.get("d:/env/jdk11"), new SimpleFileVisitor<Path>() {@Overridepublic FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {System.out.println("====>" + dir);dirCount.incrementAndGet();return super.preVisitDirectory(dir, attrs);}@Overridepublic FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {System.out.println(file);fileCount.incrementAndGet();return super.visitFile(file, attrs);}});System.out.println("dir count: " + dirCount);System.out.println("file count: " + fileCount);}
}

4、网络编程

阻塞

非阻塞

多路复用

单线程可以配合Selector完成对多个Channel可读写事件的监控,这称之为多路复用

  • 多路复用仅针对网络IO、普通文件IO没法利用多路复用
  • 如果不用Selector的非阻塞模式,线程大部分时间都在做无用功,而Selector能够保证
    • 有连接事件时才去连接
    • 有可读事件才去读取
    • 有可写事件才去写入(限于网络传输能力,Channel未必时时可写,一旦Channel可写,会触发Selector的可写事件)

监听Channel事件

可以通过下面三种方法来监听是否有事件发送,方法的返回值代表有多少channel发生了事件

方法一,阻塞直到绑定事件发生

int count = selector.select();

方法二,阻塞直到绑定事件发生,或是超时(时间单位为ms)

int count = selector.select(long timeout);

方法三,不会阻塞,也就是不管有没有事件,立刻返回,自己根据返回值检查是否有事件

int count = selector.selectNow();

👀select何时不阻塞?

  • 事件发生时

    • 客户端发起连接请求,会触发accept事件
    • 客户端发送数据过来,客户端正常、异常关闭时,都会触发read事件,另外如果发送地 数据大于buffer缓冲区,会触发多次读取事件
    • channel可写,会触发write事件
    • 在Linux下 nio bug 发生时
  • 调用selector.wakeup()

  • 调用selector.close()

  • selector 所在线程interrupt

利用多线程优化

现在都是多核CPU,设计时要充分考虑如何发挥多核CPU的优势

package com.example.netty.ch4;import com.example.netty.utils.ByteBufferUtil;
import lombok.extern.slf4j.Slf4j;import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicInteger;@Slf4j
public class MultiThreadServer {public static void main(String[] args) throws IOException {Thread.currentThread().setName("boss");ServerSocketChannel ssc = ServerSocketChannel.open();ssc.configureBlocking(false);Selector boss = Selector.open();SelectionKey bossKey = ssc.register(boss, 0, null);bossKey.interestOps(SelectionKey.OP_ACCEPT);ssc.bind(new InetSocketAddress(8080));Worker[] workers = new Worker[Runtime.getRuntime().availableProcessors()];for (int i = 0; i < workers.length; i++) {workers[i] = new Worker("worker-" + i);}AtomicInteger index = new AtomicInteger();while (true) {boss.select();Iterator<SelectionKey> iter = boss.selectedKeys().iterator();while (iter.hasNext()) {SelectionKey key = iter.next();iter.remove();if (key.isAcceptable()) {SocketChannel sc = ssc.accept();sc.configureBlocking(false);log.debug("connected...{}", sc.getRemoteAddress());log.debug("before register...{}", sc.getRemoteAddress());// 负载均衡(轮询)workers[index.getAndIncrement() % workers.length].register(sc);log.debug("after register...{}", sc.getRemoteAddress());}}}}static class Worker implements Runnable {private Thread thread;private Selector selector;private String name;private volatile boolean start = false;private ConcurrentLinkedQueue<Runnable> queue = new ConcurrentLinkedQueue<>();public Worker(String name) {this.name = name;}/*** 初始化线程和selector*/public void register(SocketChannel sc) throws IOException {if (!start) {selector = Selector.open();thread = new Thread(this, name);thread.start();start = true;}// 向队列添加了任务,但这个任务并没有立刻执行queue.add(() -> {try {sc.register(selector, SelectionKey.OP_READ, null);} catch (ClosedChannelException e) {e.printStackTrace();}});selector.wakeup(); // 唤醒 select 方法}@Overridepublic void run() {while (true) {try {selector.select();Runnable task = queue.poll();if (task != null) {// 执行了 sc.register(selector, SelectionKey.OP_READ, null);task.run();}Iterator<SelectionKey> iter = selector.selectedKeys().iterator();while (iter.hasNext()) {SelectionKey key = iter.next();iter.remove();if (key.isReadable()) {ByteBuffer buffer = ByteBuffer.allocate(16);SocketChannel channel = (SocketChannel) key.channel();channel.read(buffer);buffer.flip();ByteBufferUtil.debugAll(buffer);}}} catch (IOException e) {e.printStackTrace();}}}}
}

5、NIO vs BIO

stream vs channel

  • stream 不会自动缓冲数据,channel会利用系统提供的发送缓冲区,接收缓冲区(更为底层)
  • stream仅支持阻塞API,channel同时支持阻塞、非阻塞API,网络channel可配合selector实现多路复用
  • 两者均为全双工,即读写可以同时进行

IO模型

同步阻塞、同步非阻塞、多路复用、异步阻塞(没有此情况)、异步非阻塞

同步:线程自己去获取结果(一个线程)

异步:线程自己不去获取结果,而是由其它线程送结果(至少两个线程)

当调用一个channel.read 或 stream.read 后,会切换至操作系统内核态来完成真正数据读取,而读取又分为两个阶段,分别为:

  • 等待数据阶段
  • 复制数据阶段

IO模型:

  • 阻塞IO
  • 非阻塞IO
  • 多路复用
  • 信号驱动
  • 异步IO

零拷贝

仅只发生一次用户态到内核态的切换,数据拷贝了2次。所谓的【零拷贝】,并不是真正的无拷贝,而是在不会拷贝重复数据到JVM内存中,零拷贝的优点有:

  • 更少的用户态与内核态的切换
  • 不利用CPU计算,减少CPU缓存伪共享
  • 零拷贝适合小文件传输

AIO

AIO 用来解决数据复制阶段的阻塞问题

  • 同步意味着,在进行读写操作时,线程需要等待结果,还是相当于闲置
  • 异步意味着,在进行读写操作时,线程不必等待结果,而是将来由操作系统通过回调方式由另外的线程来获得结果

异步模型需要底层操作系统(Kernel)提供支持

  • Windows 系统通过IOCP实现了真正得异步IO

  • Linux 系统异步IO在2.6版本引入,但其底层实现还是用多路复用模拟了异步IO,性能没有优势

参考资料

https://www.bilibili.com/video/BV1py4y1E7oA

相关文章:

Netty学习笔记1

Netty学习笔记&#xff08;一&#xff09; 在的互联网环境下&#xff0c;分布式系统大行其道&#xff0c;而分布式系统的根基在于网络编程&#xff0c;而 Netty 恰恰是 Java 领域网络编程的王者。如果要致力于开发高性能的服务器程序、高性能的客户端程序&#xff0c;必须掌握…...

RISK-V品牌的中国化历程(中)

目录 1.技术优势 出道即巅峰 2.生态布道 品牌根植中国 3.应用场景 加速品牌的商业化运作 生态布道 品牌根植中国 2015年成立非盈利组织RISC-V基金会&#xff0c;目前已吸引全球28个国家327家会员&#xff0c;包括英伟达、联发科、苹果、特斯拉、谷歌、高通、IBM、三星、麻省理…...

2023.02.19 学习周报

文章目录摘要文献阅读1.题目2.摘要3.介绍4.本文贡献5.方法5.1 Local Representation Learning5.2 Global Representation Learning5.3 Item Similarity Gating6.实验6.1 数据集6.2 结果7.结论深度学习1.对偶问题1.1 拉格朗日乘数法1.2 强对偶性2.SVM优化3.软间隔3.1 解决问题3.…...

枚举类的使用方法

一、理解枚举类型 枚举类型是Java 5中新增特性的一部分&#xff0c;它是一种特殊的数据类型&#xff0c;之所以特殊是因为它既是一种类(class)类型却又比类类型多了些特殊的约束&#xff0c;但是这些约束的存在也造就了枚举类型的简洁性、安全性以及便捷性。下面先来看看如何写…...

.NET3.5安装步骤及相关问题。

.NET3.5全称 Microsoft.NETFramework3.5 最新版本-.NET4.8 第一步打开控制面板 windows系统打开控制面板 选择程序 选择.NET3.5安装。 可能会出现问题。 解决方案&#xff1a; 报错代码80240438的常用解决办法&#xff1a; 方法一&#xff1a;检测windows update servic…...

联想M7268激光打印机开机红绿灯双闪报错不打印

故障现象: 一台联想M7268激光打印机开机后电源键、复印键一起双闪,电源键闪红灯、复印键闪绿灯; 检测维修: 根据闪灯故障判断如果无卡纸异常情况下可能是激光器故障,因为以前曾经维修过一台一模一样的机器故障基本相同,先打开机器吧,把硒鼓拿出来先看看有没有卡纸,进纸…...

产品经理知识体系:7.web和app产品需求设计

web和app产品需求设计 思考 笔记 web产品设计 一、交互设计 1.以用户为中心的设计&#xff1a;功能、体验、用户&#xff1b; 将产品功能转化成用户的体验&#xff0c;功能和体验的结合。 2.交互设计模式 交互逻辑 信息结构 信息内容 界面结构 导航设计 二、视觉设计 元素的…...

强化学习概述

一、Modelfree 和 Modelbased Modelfree&#xff1a;不需要理解环境 Modelbased&#xff1a;需要理解环境&#xff0c;并且为环境建立模型 Model-free 中, 机器人只能按部就班, 一步一步等待真实世界的反馈, 再根据反馈采取下一步行动. 而 model-based, 他能通过想象来预判断接…...

NO.1嵌入式入门笔记:常用命令记录

一、前言 Linux文件目录&#xff1a; Linux Shell&#xff1a; 它负责接收用户的输入&#xff0c;根据用户的输入找到其它程序并运行。比如我们输入“ls”并回车时&#xff0c;shell 程序找到“ls”程序并运行&#xff0c;把结果打印出来。Shell有多种实现&#xff0c;我们常用…...

Shell编程

typora-copy-images-to: pictures typora-root-url: pictures 文章目录typora-copy-images-to: pictures typora-root-url: pictures本节课程目标语法和选项语法和选项3. sort工具语法和选项5.tee工具6.diff工具语法和选项7. paste工具8. tr工具语法和选项小试牛刀二、bash的特…...

网络模型OSI

网络模型OSI定义模型分布数据封装、解封过程数据链路层1.LLC逻辑链路控制子层(Logic Link Control Sub Layer)2.MAC媒介访问控制子层(Medium Acess Control Sub Layer)CSMA/CARST-CST原理OSI定义 OSI&#xff1a;Open Systems Interconnection Reference Model&#xff0c;开放…...

RT-Thread初识学习-01

1. RT-Thread 简介 1.1 RT-Thread 是什么 据不完全统计&#xff0c;世界有成千上万个 RTOS&#xff08;Real-time operating system&#xff0c;实时操作系统&#xff09;&#xff0c;RT-Thread 就是其中一个优秀的作品。 RT-Thread 内核的第一个版本是熊谱翔先生在 2006 年…...

二阶段提交事务的实现和缺点

背景 说起分布式事务&#xff0c;我们最绕不开的一个话题就是该不该使用分布式事务&#xff0c;而要理解为什么做出使用与否的决定&#xff0c;就必须要提到分布式事务中的最经典的实现&#xff1a;两阶段提交事务,本文我们就简答介绍下这个两阶段提交事务以及它的优缺点 技术…...

定点数的表示和运算

文章目录真值&#xff08;有正负号&#xff09;和机器数&#xff08;0正1负&#xff09;原码整数小数补码负数的补数正数的补数[y]~补~ > [-y]~补~反码小结移码移位运算加减法运算溢出判断真值&#xff08;有正负号&#xff09;和机器数&#xff08;0正1负&#xff09; 无符…...

java虚拟机内存分布

java虚拟机内存分布 Java虚拟机在执行java程序的过程中会把它所管理的内存划分为如下若干个不同的数据区域。 1.程序计数器 程序计数器是线程私有的&#xff0c;它占用的空间相对较小&#xff0c;用来记录当前线程字节码执行到哪一步。字节码解释器通过改变这个计数器的值来获…...

最完整的小红书带货笔记——垂直模式

最完整的小红书带货笔记——垂直模式&#xff0c;小红书直播复盘怎么做&#xff1f;#直播带货笔记 第1篇&#xff0c;带你解锁直播复盘5大要点&#xff01; #小红书店铺#小红书运营 小红书怎么发带货笔记&#xff1f; 做小红书带货的同学注意了&#xff0c;我们带货一定要发笔…...

SpringBoot实战——个人博客项目

目录 一、项目简介 二、项目整体架构 数据库模块 后端模块 前端模块 三、项目具体展示 四、项目的具体实现 1、一些准备工作 &#x1f34e;数据库、数据表的创建 &#x1f34e;设置数据库和MyBatis的配置 &#x1f34e;将前端项目引入到当前项目中 2、登录注册模块 &…...

浅谈Spring中事务管理器

由于事务部分代码在设计上整体比较简单&#xff0c;我自己觉得它在设计上没有什么特别让我眼前一亮的东西&#xff0c;所以下文更多的是侧重执行流程&#xff0c;能理解事务管理器等一众概念以及相关的变量含义&#xff0c;真正遇到Bug会调试&#xff0c;知道在什么地方打断点就…...

Python练习系统

用python给自己做个练习系统刷题吧&#xff01; #免费源码在文末公众号哈# 选择题 def xuanze():global flag2if flag21:def insert():numvar1.get()questionvar2.get()choicevar3.get()answervar4.get()with open(d:\\练习系统\\练习三3.1.pickle,rb) as file:lst1pickle.lo…...

Transformer学习笔记1

Transformer学习笔记1 翻译中&#xff0c;每个词翻译时更看重哪个原词&#xff1f; ## 注意力机制的一般性原理 典型的注意力机制 hard one-hot形式&#xff0c;但是太过专一 soft 都分布&#xff0c;但是太过泛滥 local attention 自注意力机制&#xff1a;self-atte…...

软件测试简历个人技能和项目经验怎么写?(附项目资料)

目录 前言 个人技能 项目实战经验 项目名称&#xff1a;苏州银行项目&#xff08;webapp&#xff09; 项目描述&#xff1a; 项目名称&#xff1a;中国平安项目&#xff08;webapp&#xff09; 项目描述&#xff1a; 项目名称&#xff1a;苏宁易购项目&#xff08;webapp&a…...

C语言运算符优先级和结合性一览表

所谓优先级就是当一个表达式中有多个运算符时&#xff0c;先计算谁&#xff0c;后计算谁。 运算符的优先级从高到低大致是&#xff1a;单目运算符、算术运算符、关系运算符、逻辑运算符、条件运算符、赋值运算符()和逗号运算符 简单记就是&#xff1a;&#xff01; > 算术运…...

Java8介绍

Java 8 Java 8 把函数式编程里的一些思想融入到 Java 的语法中&#xff0c;让我们可以用更少的时间写出高效的代码。 Java 8的优势&#xff1a; 代码行更少Lambda表达式Stream API便于并行减少空指针JVM优化兼容老版本 Lambda Lambda表达式是一段可以传递的代码&#xff0…...

Java 基准测试

Java 基准测试maven依赖简单使用执行多个函数BenchmarkMode(Mode.AverageTime) 运行模式OutputTimeUnit(TimeUnit.NANOSECONDS) 报告结果时间单位Warmup(iterations 5,time 1,timeUnit TimeUnit.SECONDS) 预热参数Measurement(iterations 5,time 1,timeUnit TimeUnit.SEC…...

普通护照出国免签及落地签国家和地区

1.互免签协议的国家&#xff08;双向免签&#xff09; 序号 协议国 限制条件 生效日期 1 阿联酋 停留不超过30天 2018.01.16 2 巴巴多斯 停留不超过30天 2017.06.01 3 巴哈马 停留不超过30天 2014.02.12 4 白俄罗斯 停留不超过30天 2018.8.10 5 波黑 停留不超…...

20230219 质心和重心的区别和性质

质心&#xff1a;&#xff08;无需重力场的前提&#xff09;所有质点的位置关于它们的质量的加权平均数。 重心&#xff1a;&#xff08;需要重力场的前提&#xff09;重力对系统中每个质点关于重心的力矩之和为零。 质心&#xff1a; xˉ∑i1nmixi∑i1nmi,yˉ∑i1nmiyi∑i1nmi…...

maven多环境配置

maven多环境配置 参考网址: https://mp.weixin.qq.com/s/-e74bd2wW_RLx7i4YF5M2w https://mp.weixin.qq.com/s/3p53kBHqys58QdMme6lR4A 项目地址 https://gitee.com/shao_ming314/maven-profile-dir 项目说明 该项目基于目录进行多环境配置 , 具体的配置文件在 src/resource…...

设计模式之中介模式与解释器模式详解和应用

目录1 中介模式详解1.1 中介模式的定义1.1.1 中介者模式在生活场景中应用1.1.2 中介者模式的使用场景1.2 中介模式的通用实现1.2.1 类图设计1.2.2 代码实现1.3 中介模式应用案例之聊天室1.3.1 类图设计1.3.2 代码实现1.4 中介者模式在源码中应用1.4.1 jdk中Timer类1.5 中介者模…...

2023年全国最新交安安全员精选真题及答案1

百分百题库提供交安安全员考试试题、交安安全员考试预测题、交安安全员考试真题、交安安全员证考试题库等&#xff0c;提供在线做题刷题&#xff0c;在线模拟考试&#xff0c;助你考试轻松过关。 一、单选题&#xff1a; 1.对施工组织设计中的安全技术措施或者专项施工方案是否…...

chrome插件开发备忘录

文章目录前言要点通信方式注意事项参考前言 第一次接触到插件开发&#xff0c;起因是我用了十多年的一键上传需要升级了。之前的版本来自于有道云&#xff0c;是通过在书签栏加一个书签&#xff0c;然后将上传功能注入到当前页面的方式来实现的。一直也用得挺好&#xff0c;挺…...

厦门网站建设咨询/内容营销策略有哪些

文章目录1 Git Dos窗口中操作1.1 首先在码云上新建一个项目&#xff0c;如下图所示1.2 在本地新建或选择一个文件夹1.3 进入新建或选择的文件夹&#xff0c;鼠标右键选择git bash here&#xff0c;弹出dos窗口1.4 在弹出dos窗口登录仓库地址1.5 继续在窗口输入 git init1.6 继续…...

成都设计公司展览/电脑优化大师哪个好

使用织梦dedecms建设网站的朋友都知道&#xff0c;织梦文章列表调用缩略图的时候&#xff0c;如果文章没有图片&#xff0c;会显示系统默认的图defaultpic.gif&#xff0c;但是一些朋友想要修改织梦dedecms默认缩略图存放文件夹路径&#xff0c;应该怎么做呢&#xff1f;织梦默…...

大学做机器人比赛的网站论坛/衡水seo排名

参数配置篇 我的600D基本设置: 一、菜单中的基本设置&#xff1a;&#xff08;括号是VV的设置&#xff09; 1、画质&#xff1a;RAW&#xff0b;jpeg&#xff08;大/优&#xff09;。raw这种格式细节更丰富&#xff0c;后期可随意调整白平衡、清晰度、色彩饱和度、亮度、对比度…...

小吃网站怎么做/友链交换网站

let 和 var 的区别 最近很多前端的朋友去面试被问到let和var的区别&#xff0c;其实阮一峰老师的ES6中已经很详细介绍了let的用法和var的区别。我简单总结一下&#xff0c;以便各位以后面试中使用。 ES6 新增了let命令&#xff0c;用来声明局部变量。它的用法类似于var&#…...

科技是第一生产力人才是第一资源创新是第一动力判断题/seo推广和百度推广的区别

1. 过程概述 Python先把代码&#xff08;.py文件&#xff09;编译成字节码&#xff0c;交给字节码虚拟机&#xff0c;然后虚拟机一条一条执行字节码指令&#xff0c;从而完成程序的执行。 2. 字节码 字节码在Python虚拟机程序里对应的是PyCodeObject对象。 .pyc文件是字节码在磁…...

龙江网站建设/新闻发稿软文推广

赛博朋克2077配置要求终于出炉了&#xff0c;在官方公布之前&#xff0c;很多玩家都在想会不会要求很高&#xff0c;甚至有部分玩家已经开始攒钱换机器了。不过看到游戏的配置要求参数之后可以放心了&#xff0c;本作的配置相对于这款游戏的体量和制作来说&#xff0c;已经算是…...