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

专业建站公司服务/新手怎么做网络销售

专业建站公司服务,新手怎么做网络销售,求职网,怎样架设网站1.原子累加器 示例代码: public class TestAtomicAdder {public static void main(String[] args) {for (int i 0; i < 5; i) {demo(() -> new AtomicLong(0),(adder) -> adder.getAndIncrement());}for (int i 0; i < 5; i) {demo(() -> new LongAdder(),(…

1.原子累加器

示例代码:

public class TestAtomicAdder {public static void main(String[] args) {for (int i = 0; i < 5; i++) {demo(() -> new AtomicLong(0),(adder) -> adder.getAndIncrement());}for (int i = 0; i < 5; i++) {demo(() -> new LongAdder(),(adder) -> adder.increment());}}/*** @param adderSupplier 提供者 无中生有 ()->结果* @param action        消费者 一个参数没结果* @param <T>*/private static <T> void demo(Supplier<T> adderSupplier, Consumer<T> action) {T adder = adderSupplier.get();long start = System.nanoTime();List<Thread> ts = new ArrayList<>();//4个线程,每个累加5万次,最终结果是200000for (int i = 0; i < 4; i++) {ts.add(new Thread(() -> {for (int j = 0; j < 50000; j++) {action.accept(adder);}}));}ts.forEach(t -> t.start());ts.forEach(t -> {try {t.join();} catch (InterruptedException e) {e.printStackTrace();}});long end = System.nanoTime();System.out.println(adder + " cost(ns):" + (end - start) / 1000_000);}
}

比较 AtomicLong 与 LongAdder:
在这里插入图片描述

LongAdder累加器性能提升的原因很简单,就是在有竞争时,设置多个累加单元,Therad-0累加Cell[0],而Thread-1累加Cell[1]… 最后将结果汇总.这样它们在累加时操作不同的Cell变量,因此减少了CAS重试失败,从而提高性能;

1.1.LongAdder源码分析

1>.LongAdder是并发大师Doug Lea(大哥李)的作品,设计的非常精巧;

2>.LongAdder类有几个关键域:

// 累加单元数组,懒惰初始化
// transient关键字作用在是序列化的时候保证这些域不会被序列化
transient volatile Cell[] cells;// 基础值,如果没有竞争,则用cas累加这个域
transient volatile long base;// 在cells创建或扩容时,置为1,表示加锁
transient volatile int cellsBusy;

3>.CAS锁

// 不要用于实践!!!
public class LockCas {private AtomicInteger state = new AtomicInteger(0);public void lock() {while (true) {if (state.compareAndSet(0, 1)) {break;}}}public void unlock() {log.debug("unlock...");state.set(0);}
}//测试代码
LockCas lock = new LockCas();
new Thread(() -> {log.debug("begin...");lock.lock();try {log.debug("lock...");sleep(1);} finally {lock.unlock();}
}).start();new Thread(() -> {log.debug("begin...");lock.lock();try {log.debug("lock...");} finally {lock.unlock();}
}).start();

4>.缓存行(hang)伪共享(一个缓存行加入了多个内存cell对象被称为伪共享)
其中Cell即为累加单元

// 防止缓存行伪共享,防止一个缓存行容纳多个内存cell对象
@sun.misc.Contended
static final class Cell {volatile long value;Cell(long x) { value = x; }// 最重要的方法, 用cas方式进行累加, prev表示旧值, next表示新值final boolean cas(long prev, long next) {return UNSAFE.compareAndSwapLong(this, valueOffset, prev, next);}// 省略不重要代码
}

1.1.1.LongAdder#add()源码

public void add(long x) {// as为累加单元数组// b为基础值// x为累加值Cell[] as; long b, v; int m; Cell a;// 进入 if 的两个条件// 1.as有值,表示已经发生过竞争, 进入if// 2.cas给base累加时失败了,表示base发生了竞争,进入ifif ((as = cells) != null || !casBase(b = base, b + x)) {// uncontended表示cell没有竞争boolean uncontended = true;// as还没有创建// 当前线程对应的cell还没有// cas给当前线程的cell累加失败uncontended=false(a为当前线程的cell)if (as == null || (m = as.length - 1) < 0 ||(a = as[getProbe() & m]) == null ||!(uncontended = a.cas(v = a.value, v + x)))// 进入cell数组创建、cell创建的流程longAccumulate(x, null, uncontended);}
}

在这里插入图片描述

1.1.2.Striped64#longAccumulate()源码

final void longAccumulate(long x, LongBinaryOperator fn,boolean wasUncontended) {int h;// 当前线程还没有对应的cell,需要随机生成一个h值用来将当前线程绑定到cellif ((h = getProbe()) == 0) {// 初始化probeThreadLocalRandom.current(); // force initialization// h对应新的probe值,用来对应(/占用)cell
h = getProbe();wasUncontended = true;}// collide为true表示需要扩容boolean collide = false;                // True if last slot nonemptyfor (;;) {Cell[] as; Cell a; int n; long v;// 已经有了cellsif ((as = cells) != null && (n = as.length) > 0) {// 还没有cellif ((a = as[(n - 1) & h]) == null) {// 为cellsBusy加锁,创建cell,cell的初始累加值为x// 成功则 break,否则继续continue循环if (cellsBusy == 0) {       // Try to attach new CellCell r = new Cell(x);   // Optimistically createif (cellsBusy == 0 && casCellsBusy()) {boolean created = false;try {               // Recheck under lockCell[] rs; int m, j;if ((rs = cells) != null &&(m = rs.length) > 0 &&rs[j = (m - 1) & h] == null) {rs[j] = r;created = true;}} finally {cellsBusy = 0;}if (created)break;continue;           // Slot is now non-empty}}collide = false;}// 有竞争,改变线程对应的cell来重试caselse if (!wasUncontended)       // CAS already known to failwasUncontended = true;      // Continue after rehash// cas尝试累加,fn配合LongAccumulator不为null,配合LongAdder为null
else if (a.cas(v = a.value, ((fn == null) ? v + x :fn.applyAsLong(v, x))))break;// 如果cells长度已经超过了最大长度,或者已经扩容,改变线程对应的cell来重试caselse if (n >= NCPU || cells != as)collide = false;            // At max size or stale// 确保collide为false进入此分支,就不会进入下面的else if进行扩容了
else if (!collide)collide = true;// 加锁else if (cellsBusy == 0 && casCellsBusy()) {try {if (cells == as) {      // Expand table unless staleCell[] rs = new Cell[n << 1];for (int i = 0; i < n; ++i)rs[i] = as[i];cells = rs;}} finally {cellsBusy = 0;}collide = false;// 加锁成功,扩容continue;                   // Retry with expanded table}// 改变线程对应的cell对象h = advanceProbe(h);}// 还没有cells,尝试给cellsBusy加锁else if (cellsBusy == 0 && cells == as && casCellsBusy()) {// 加锁成功,初始化cells,最开始长度为2,并填充一个cellboolean init = false;try {                           // Initialize tableif (cells == as) {Cell[] rs = new Cell[2];rs[h & 1] = new Cell(x);cells = rs;init = true;}} finally {cellsBusy = 0;}if (init)// 成功则break;break;}// 上两种情况失败,尝试给base累加else if (casBase(v = base, ((fn == null) ? v + x :fn.applyAsLong(v, x))))break;                          // Fall back on using base}
}

在这里插入图片描述在这里插入图片描述
每个线程刚进入longAccumulate()时,会尝试对应(/占用)一个cell对象(找到一个位置)
在这里插入图片描述

1.1.3.LongAdder#sum()源码

public long sum() {Cell[] as = cells; Cell a;long sum = base;if (as != null) {for (int i = 0; i < as.length; ++i) {if ((a = as[i]) != null)//将Cells数组中的每个元素进行累加sum += a.value;}}return sum;
}

扩展: 缓存与内存的速度比较

1>.CPU内存结构:
在这里插入图片描述
2>.CPU访问不同的缓存和内存耗费的时钟周期
在这里插入图片描述

①.CPU与内存的速度差异很大,需要靠预读数据至缓存来提升效率;
②.缓存以缓存行为单位,每个缓存行对应着一块内存,一般是64byte(8个long);
③.缓存的加入会造成数据副本的产生,即同一份数据会缓存在不同核心的缓存行中;
④.CPU要保证数据的一致性,如果某个CPU核心更改了数据,其它CPU核心对应的整个缓存行(64byte)必须全部失效;
在这里插入图片描述
⑤.由于内存Cell是数组形式,在内存中是连续存储的,一个内存Cell为24字节(16字节的对象头和8字节的value),因此缓存行可以存下2个内存Cell对象.这样问题来了:

  • Core-0要修改Cell[0]
  • Core-1要修改Cell[1]

无论谁修改成功,都会导致对方Core的缓存行失效,比如Core-0中Cell[0]=6000,Cell[1]=8000要累加Cell[0]=6001,Cell[1]=8000,这时会让Core-1的缓存行失效;
⑥."@sun.misc.Contended"就是用来解决这个问题的,它的原理是在使用此注解的对象或字段的前后各增加128字节大小的padding(填充内存Cell),从而让CPU将(不同的)对象预读至缓存时占用不同的缓存行,这样不会造成对方缓存行的失效;
在这里插入图片描述

2.Unsafe对象

2.1.概述

1> Unsafe对象提供了非常底层的,操作内存、线程的方法,Unsafe对象不能直接调用,只能通过反射获得;

2>.示例代码:

public class TestUnsafeDemo1 {public static void main(String[] args) throws Exception {//通过反射获取到unsafe对象,这里的参数"theUnsafe"是固定的写法,对应着unsafe对象中的(类类型)成员变量Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");//由于unsafe对象中"theUnsafe"成员变量是"private"私有的,因此要设置访问权限theUnsafe.setAccessible(true);//通过成员变量获取到所属的unsafe对象//由于unsafe对象中"theUnsafe"成员变量是静态的,因此这里原本的对象参数就是nullUnsafe unsafe = (Unsafe) theUnsafe.get(null);System.out.println(unsafe);  //sun.misc.Unsafe@7ea987ac}
}

3>.封装成工具类:

public class UnsafeAccessor {static Unsafe unsafe;static {try { Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");theUnsafe.setAccessible(true);unsafe = (Unsafe) theUnsafe.get(null);} catch (NoSuchFieldException | IllegalAccessException e) {throw new Error(e);}}static Unsafe getUnsafe() {return unsafe;}
}

2.2.Unsafe CAS操作

1>.使用Unsafe对象通过CAS机制线程安全的修改对象的成员变量:

@Slf4j
public class TestUnsafeCasDemo1 {public static void main(String[] args) throws Exception {//获取unsafe对象Unsafe unsafe = UnsafeAccessor.getUnsafe();//获取对象中某个成员变量的偏移地址long idOffset = unsafe.objectFieldOffset(Teacher.class.getDeclaredField("id"));long nameOffset = unsafe.objectFieldOffset(Teacher.class.getDeclaredField("name"));//执行CAS操作Teacher teacher = new Teacher();boolean b = unsafe.compareAndSwapInt(teacher, idOffset, 0, 1);boolean b1 = unsafe.compareAndSwapObject(teacher, nameOffset, null, "张三");//打印结果log.info(teacher.toString());}
}@Data
@NoArgsConstructor
class Teacher {volatile int id;volatile String name;
}//unsafe对象封装
class UnsafeAccessor {static Unsafe unsafe;static {try {Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");theUnsafe.setAccessible(true);unsafe = (Unsafe) theUnsafe.get(null);} catch (NoSuchFieldException | IllegalAccessException e) {throw new Error(e);}}static Unsafe getUnsafe() {return unsafe;}
}

在这里插入图片描述

2.3.模拟实现原子整数

1>.以转账为例:

public class TestCustomAtomicIntegerDemo1 {public static void main(String[] args) {Account1.demo(new MyAtomicInteger(200));}
}//自定义的原子整数类
class MyAtomicInteger implements Account1 {private volatile int value;private static final long valueOffset;private static final Unsafe UNSAFE;static {UNSAFE = UnsafeAccessorUtil.getUnsafe();try {valueOffset = UNSAFE.objectFieldOffset(MyAtomicInteger.class.getDeclaredField("value"));} catch (NoSuchFieldException e) {e.printStackTrace();throw new RuntimeException();}}public MyAtomicInteger(int value) {this.value = value;}public int getValue() {return this.value;}public void decrement(int amount) {while (true) {int prev = this.value;int next = prev - amount;if (UNSAFE.compareAndSwapInt(this, valueOffset, prev, next)) {break;}}}@Overridepublic Integer getBalance() {return this.getValue();}@Overridepublic void withDraw(int amount) {this.decrement(amount);}
}//unsafe工具类
class UnsafeAccessorUtil {static Unsafe unsafe;static {try {Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");theUnsafe.setAccessible(true);unsafe = (Unsafe) theUnsafe.get(null);} catch (NoSuchFieldException | IllegalAccessException e) {throw new Error(e);}}static Unsafe getUnsafe() {return unsafe;}
}//封装转账相关的方法
interface Account1 {//获取余额Integer getBalance();//取款void withDraw(int amount);/*** 方法内会启动20个线程,每个线程做(-10元)的操作* 如果初始余额为200那么正确的结果应当是 0*/static void demo(Account1 account) {List<Thread> ts = new ArrayList<>();long start = System.nanoTime();for (int i = 0; i < 20; i++) {ts.add(new Thread(() -> {account.withDraw(10);}));}ts.forEach(Thread::start);ts.forEach(t -> {try {t.join();} catch (InterruptedException e) {e.printStackTrace();}});long end = System.nanoTime();System.out.println(account.getBalance()+ " cost: " + (end - start) / 1000_000 + " ms");}
}

在这里插入图片描述

相关文章:

共享模型之无锁(三)

1.原子累加器 示例代码: public class TestAtomicAdder {public static void main(String[] args) {for (int i 0; i < 5; i) {demo(() -> new AtomicLong(0),(adder) -> adder.getAndIncrement());}for (int i 0; i < 5; i) {demo(() -> new LongAdder(),(…...

微信小程序 Springboot校运会高校运动会管理系统

3.1小程序端 小程序登录页面&#xff0c;用户也可以在此页面进行注册并且登录等。 登录成功后可以在我的个人中心查看自己的个人信息或者修改信息等 在广播信息中我们可以查看校运会发布的一些信息情况。 在首页我们可以看到校运会具体有什么项目运动。 在查看具体有什么活动我…...

走进独自开,带你轻松干副业

今天给大家分享一个开发者的福利平台——独自开&#xff08;点击直接注册&#xff09;&#xff0c;让你在家就能解决收入问题。 文章目录一、平台介绍二、系统案例三、获取收益四、使用平台1、用户注册2、用户认证3、任务报价五、文末总结一、平台介绍 简单说明 独自开信息科技…...

SpringBoot+Vue实现师生健康信息管理系统

文末获取源码 开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7/8.0 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a;Maven3.3.9 浏…...

数据库第四章节第三次作业内容

1、显示所有职工的基本信息。 2、查询所有职工所属部门的部门号&#xff0c;不显示重复的部门号。 3、求出所有职工的人数。 4、列出最高工和最低工资。 5、列出职工的平均工资和总工资。 6、创建一个只有职工号、姓名和参加工作的新表&#xff0c;名为工作日期表…...

一篇五分生信临床模型预测文章代码复现——FIgure 9.列线图构建,ROC分析,DCA分析 (四)

之前讲过临床模型预测的专栏,但那只是基础版本,下面我们以自噬相关基因为例子,模仿一篇五分文章,将图和代码复现出来,学会本专栏课程,可以具备发一篇五分左右文章的水平: 本专栏目录如下: Figure 1:差异表达基因及预后基因筛选(图片仅供参考) Figure 2. 生存分析,…...

神经网络实战--使用迁移学习完成猫狗分类

前言&#xff1a; Hello大家好&#xff0c;我是Dream。 今天来学习一下如何使用基于tensorflow和keras的迁移学习完成猫狗分类&#xff0c;欢迎大家一起前来探讨学习~ 本文目录&#xff1a;一、加载数据集1.调用库函数2.加载数据集3.数据集管理二、猫狗数据集介绍1.猫狗数据集介…...

Attention机制 学习笔记

学习自https://easyai.tech/ai-definition/attention/ Attention本质 Attention&#xff08;注意力&#xff09;机制如果浅层的理解&#xff0c;跟他的名字非常匹配。他的核心逻辑就是“从关注全部到关注重点”。 比如我们人在看图片时&#xff0c;对图片的不同地方的注意力…...

数据类型与运算符

1.字符型作用: 字符型变量用于显示单个字符语法: char cc a ;注意1: 在显示字符型变量时&#xff0c;用单引号将字符括起来,不要用双引号注意2: 单引号内只能有一个字符&#xff0c;不可以是字符串C和C中字符型变量只占用1个字节。字符型变是并不是把字符本身放到内存中存储&am…...

算法刷题-二叉树的锯齿形层序遍历、用栈实现队列 栈设计、买卖股票的最佳时机 IV

文章目录二叉树的锯齿形层序遍历&#xff08;树、广度优先搜索&#xff09;用栈实现队列&#xff08;栈、设计&#xff09;买卖股票的最佳时机 IV&#xff08;数组、动态规划&#xff09;二叉树的锯齿形层序遍历&#xff08;树、广度优先搜索&#xff09; 给定一个二叉树&…...

华为OD机试 - 最小传递延迟(Python)| 代码编写思路+核心知识点

最小传递延迟 题目 通讯网络中有 N 个网络节点 用 1 ~ N 进行标识 网络通过一个有向无环图进行表示 其中图的边的值,表示节点之间的消息传递延迟 现给定相连节点之间的延时列表 times[i]={u,v,w} 其中 u 表示源节点,v 表示目的节点,w 表示 u 和 v 之间的消息传递延时 请计…...

集中供热调度系统天然气仪表内网仪表图像识别案例

一、项目需求 出于能耗采集与冬季集中供暖工作的节能和能耗分析需要&#xff0c;要采集现场的6块天然气表计&#xff0c;并存储进入客户的mySQL数据库中&#xff0c;现场采集的表计不允许接线&#xff0c;且网络环境为内网环境&#xff0c;需要采集表计数据并存入数据库&#…...

笔试题-2023-复旦微-数字IC设计【纯净题目版】

回到首页:2023 数字IC设计秋招复盘——数十家公司笔试题、面试实录 推荐内容:数字IC设计学习比较实用的资料推荐 题目背景 笔试时间:2022.07.26应聘岗位:数字前端工程师笔试时长:120min笔试平台:赛码题目类型:基础题(10道)、选做题(10道)、验证题(5道)主观评价 难…...

【Linux】冯诺依曼体系结构和操作系统概念

文章目录&#x1f3aa; 冯诺依曼体系结构&#x1f680;1.体系概述&#x1f680;2.CPU和内存的数据交换&#x1f680;3.体系结构中数据的流动&#x1f3aa; 操作系统概念理解&#x1f680;1.简述&#x1f680;2.设计目的&#x1f680;3.定位&#x1f680;4.理解&#x1f680;5.管…...

HTML5之HTML基础学习笔记

列表标签 列表的应用场景 场景&#xff1a;在网页中按照行展示关联性的内容&#xff0c;如&#xff1a;新闻列表、排行榜、账单等特点&#xff1a;按照行的方式&#xff0c;整齐显示内容种类&#xff1a;无序列表、有序列表、自定义列表 这是老师PPT上的内容&#xff0c; 列表…...

FreeRTOS信号量 | FreeRTOS十

目录 说明&#xff1a; 一、信号量 1.1、信号量简介 1.2、信号量特点 二、二值信号量 2.1、二值信号量简介 2.2、获取与释放二值信号量函数 2.3、二值信号量使用过程与相关API函数 2.4、创建二值信号量函数了解 2.5、释放二值信号量了解 2.6、获取二值信号量了解 三…...

【SpringBoot】SpringBoot常用注解

一、前言首先这里说的SpringBoot常用注解是指在我们开发项目过程中&#xff0c;我们经常使用的注解&#xff0c;包含Spring、SpringBoot、SpringCloud、SpringMVC等这些框架中的注解&#xff0c;而不仅仅是SpringBoot中的注解。这里只是作一个注解列举&#xff0c;每个注解具体…...

数据一致性

目录一、AOP 动态代理切入方法(1) Aspect Oriented Programming(2) 切入点表达式二、SpringBoot 项目扫描类(1) ResourceLoader 扫描类(2) Map 的 computeIfAbsent 方法(3) 反射几个常用 api① 创建一个测试注解② 创建测试 PO 类③ 反射 api 获取指定类的指定注解信息(4) 返回…...

Docker不做虚拟化内核,对.NET有什么影响?

引子前两天刷抖音&#xff0c;看见了这样一个问题。问题&#xff1a;容器化不做虚拟内核&#xff0c;会有什么弊端&#xff1f;Java很多方法会跟CPU的核数有关&#xff0c;这个时候调用系统函数&#xff0c;读到的是宿主机信息&#xff0c;而不是我们限制资源的大小。思考&…...

HTML总结

CSS代码风格 空格规范&#xff1a; 1. 属性值前面&#xff0c;冒号后面&#xff0c;保留一个空格&#xff1b; 2. 选择器&#xff08;标签&#xff09;和大括号中间保留空格。 基本语法概述&#xff1a; 1.HTML标签是由尖括号包围的关键词&#xff0c;如<html> 2.HTM…...

ByteHouse:基于ClickHouse的实时数仓能力升级解读

更多技术交流、求职机会&#xff0c;欢迎关注字节跳动数据平台微信公众号&#xff0c;回复【1】进入官方交流群 ByteHouse是火山引擎上的一款云原生数据仓库&#xff0c;为用户带来极速分析体验&#xff0c;能够支撑实时数据分析和海量数据离线分析。便捷的弹性扩缩容能力&…...

[SSD固态硬盘技术 15] FTL映射表的神秘面纱

为什么需要映射表?固态硬盘的存储器件采用的是闪存[5],具有以下几个特点: (1)读写基本单位是以页(Page)为单位,擦除是以块(Block)为单位。...

浅析依赖注入框架的生命周期(以 InversifyJS 为例)

在上一篇介绍了 VSCode 的依赖注入设计&#xff0c;并且实现了一个简单的 IOC 框架。但是距离成为一个生产环境可用的框架还差的很远。 行业内已经有许多非常优秀的开源 IOC 框架&#xff0c;它们划分了更为清晰地模块来应对复杂情况下依赖注入运行的正确性。 这里我将以 Inv…...

HER2靶向药物研发进展-销售数据-上市药品前景分析

HER2长期作为肿瘤领域的热门靶点之一&#xff0c;其原因是它在多部位、多种形式的癌症中均有异常的表达&#xff0c;据研究表明HER2除了在胃癌、胆道癌、胆管癌、乳腺癌、卵巢癌、结肠癌、膀胱癌、肺癌、子宫颈癌、子宫浆液性子宫内膜癌、头颈癌、食道癌中的异常表达还存在于多…...

【第38天】不同路径数问题 | 网格 dp 入门

本文已收录于专栏&#x1f338;《Java入门一百例》&#x1f338;学习指引序、专栏前言一、网格模型二、【例题1】1、题目描述2、解题思路3、模板代码4、代码解析5.原题链接三、【例题2】1、题目描述2、解题思路3、模板代码4、代码解析5.原题链接三、推荐专栏四、课后习题序、专…...

LINUX之链接命令

链接命令学习目标能够说出软链接的创建方式能够说出硬链接的创建方式1. 链接命令的介绍链接命令是创建链接文件&#xff0c;链接文件分为:软链接硬链接命令说明ln -s创建软链接ln创建硬链接2. 软链接类似于Windows下的快捷方式&#xff0c;当一个源文件的目录层级比较深&#x…...

1628_MIT 6.828 xv6_chapter0操作系统接口

全部学习汇总&#xff1a; GreyZhang/g_unix: some basic learning about unix operating system. (github.com) 这本书最初看名字以为是对早期unix的一个解读&#xff0c;但是看了开篇发现 不完全是&#xff0c;只是针对JOS教学OS系统来做的一些讲解。 Xv6是对UNIX v6的重新实…...

使用 Sahi 实现 Web 自动化测试

Sahi 是 Tyto Software 旗下的一个基于业务的开源 Web 应用自动化测试工具。Sahi 运行为一个代理服务器&#xff0c;并通过注入 JavaScript 来访问 Web 页面中的元素。Sahi 支持 HTTPS 并且独立于 Web 站点&#xff0c;简单小巧却功能强大。它相对于 Selenium 等自动化测试工具…...

天津菲图尼克科技携洁净及无菌防护服解决方案与您相约2023生物发酵展

BIO CHINA 生物发酵产业一年一度行业盛会&#xff0c;由中国生物发酵产业协会主办&#xff0c;上海信世展览服务有限公司承办&#xff0c;2023第10届国际生物发酵产品与技术装备展览会&#xff08;济南&#xff09;于2023年3月30-4月1日在山东国际会展中心&#xff08;济南市槐…...

Java 网络编程详解

1、什么是网络编程 在网络通信协议下&#xff0c;不同计算机上运行的程序&#xff0c;可以进行数据传输。 应用场景&#xff1a;     1、即时通信 2、网游对战 3、邮件等等 Java中可以使用java.net包下的技术轻松开发出常见的网络应用程序 2、网络编程三要素 2.1 IP地址 要…...