(java)进程和线程的联系和区别 。Java如何进行多线程编程?Thread 类及常见方法。

目录

进程 

1.进程具有独立性

————  虚拟地址空间

线程

 为什么要引入多个线程?

 多线程注意点

⁜⁜总结:线程和进程的区别和联系⁜⁜ (经典面试题)

Java如何进行多线程编程?

创建线程 

——方法1 继承 Thread 类

——方法2 实现 Runnable 接口

—— 使用Runnable的写法 和 直接继承 Thread 有什么区别?

匿名内部类 方法 

继承 Thread,重写run,但是使用匿名内部类 

实现Runnable,重写run,使用匿名内部类

基于 lambda 表达式 【推荐 比前面的方法都简单】

—— lambda 表达式 (介绍了回调函数)

 Thread 类的其他常见使用方法

—— Thread 的常见构造方法

—— Thread 的几个常见属性

 启动线程-start() (含经典面试题,start 和 run的区别)

中断线程 

-- 方案一 

--  方案二

线程等待 


进程 

1.进程具有独立性

首先介绍一下

————  虚拟地址空间

在这之前还要了解一下 —— “物理内存”

在早期的操作系统中,程序运行时分配的内存,就是 “物理内存”。

这个物理内存简单理解,就可以看成是一个宿舍楼,宿舍楼里有很多房间,每个房间占一个字节,且每个房间都有编号,这个编号就是“内存地址”。

那现在分配内存就直接从物理内存上分配,但是这时候就会出现问题

而操作系统需要给进程提供一个稳定的运行环境 ,上述的肯定不行。

所以操作系统就引入了 “ 虚拟地址空间 ” 的概念,  不直接分配物理内存了,而是分配一块虚拟的内存空间。操作系统对于内存又进行了一层抽象,如下图。

正是这样的机制,才带来了进程的独立性 。

进程是 资源分配 的基本单位。

(一个系统中可以有很多的进程,每个进程,都有自己的资源)

线程

在Java这样的生态中,不是很鼓励 多进程编程,更鼓励使用 多线程编程 

 为什么要引入多个线程?

为了实现 并发编程  ———— 当前的时代是一个 多核CPU的时代。

虽然多程 实现 并发编程,也是很不错的,但是,多程编程模式 太重了,效率不高,不管是创建,销毁,还是调度一个进程,消耗时间都比较多, 

总的来说,就是多进程 开销比较大,效率比较低。 (进程的开销主要是消耗在了申请资源上,进程是资源分配的基本单位

为了解决上述问题,我们就引入了 “线程(Thread)”。(也叫 “轻量级进程”)

创建,销毁,还是调度一个线程,都比进程要快。

但是线程是不能独立存在的,他必须依附于线程,进程包含线程 。

进程可以包含一个或多个线程。 也就是说,一个进程,最开始至少要包含一个线程,这个线程负责完成 执行代码的工作,也可以根据需要 创建更多的线程,来实现 "并发编程" 的效果。

每个线程都可以独立执行一些代码。 

实际情况,一个进程里有多个线程,而每个线程 ,都是可以独立进行调度的 ,每个线程也都有状态,优先级,上下文,记账信息......

一个进程可能使用一个PCB 或 多个PCB表示,每个PCB 对应到一个线程

上述结构决定了线程的特点

  1. 每个线程都可以 独立 在CPU上调度执行
  2. 同一个进程里的多个线程,共用同一份 内存空间 和 文件资源

所以创建线程的时候 不需要重新 申请资源 ,直接 复用 之前已经给 进程 分配好的资源。

这样就省去了 资源分配的开销,于是创建效率就高了。

画图捋一遍

得出 线程 是 调度执行 的基本单位。 

(一个进程中,可以有很多的线程,每一个 线程 都能 独立调度执行,共享 内存/硬盘 资源)

上述对于 多进程 多线程 的描述还是比较抽象的,那举一个生活上的例子 。

假如,就是现在有个院子,院子里有条生产线,现在产品销量比较好,老板想扩大一下规模,想多搞一条生产线,那现在就是有两个方案。  

方案一: 

在搞一个院子,那就有两条生产线了,但是再找一个院子,成本比较高。

方案二 :

 

在同一个院子里再搞一条生产线,是独立的,各自都能生产,但是这两个生产线共用一个院子,一组工人,一套物流体系,这样就节约了成本 还 提高了生产力 (资本家呀~)

方案一就使用了 多进程的方式 方案二就使用了 多线程的方式。

 多线程注意点

  1. 当到了一定程度时,再进一步增加线程数目时,效率无法进一步提升,反而会因为要调度     的线程数目太多,时调度的开销更大,反而会降低了效率。
  2. 当线程数目多了,可能就会产生一定的冲突,称为 "线程不安全问题" 。
  3. 如果一个线程抛出异常,没有被妥善处理(catch),就容易把整个进程都搞崩溃,那其他线程也就都没了。

⁜⁜总结:线程和进程的区别和联系⁜⁜ (经典面试题)

  1. 进程 可以包含一个或多个 线程
  2. 进程和线程都是用来实现 “并发编程” 场景的,但是线程比进程更轻量,更高效
  3. 在同一个进程里的线程,共用同一份资源(内存 和 硬盘),省去了申请资源的开销
  4. 进程具有独立性,一个进程挂了,不会影响到其他进程;同一个 进程 里的 线程,是可能会相互影响的 (线程安全问题 + 线程出现异常)
  5. 进程是资源分配的基本单位,线程是调度执行的基本单位。

Java如何进行多线程编程?

在java中使用线程,一般有下面几步

  • 创建线程
  • 启动线程
  • 中断线程
  • 线程等待 

创建线程 

线程是操作系统的概念。操作系统提供了一些API(应用程序接口),可以操作线程。

Java就利用 (线程)Thread类 针对上述系统API进行了进一步的抽象和封装(为了跨平台) 这样程序员只需要掌握这一套API就可以了。 

那java是如何创建线程的呢,接下来介绍

——方法1 继承 Thread 类

Thread类是Java标准库内置的类,在 java.lang 这个包下。

使用Thread类,创建 Thread对象,进一步就可以操作 系统内部的 线程了。 

继承 Thread 来创建一个线程类 (重写run),创建 MyThread 类的实例,,调用 start 方法启动线程

前面介绍了每个线程都是一个独立的执行流,每个线程都可以执行一系列的逻辑(代码),

那一个线程跑起来,该从那个代码开始执行呢?从入口方法(run方法)开始执行。

运行一个java程序,就跑起来一个java进程,而一个进程里至少有一个线程——主线程,主线程的入口方法就是 main方法 。

但是其他线程此时还只是一个”定义”,要想执行,还要“调用”,在主线程里调用。 具体该如何调用,如下:

 

⁜为什么我们上面的是run方法,但是这里调用的却是 start方法呢?

  • start 和 run 都是 Thread 的成员
  • 但是 run 只是描述了线程的入口(线程要做什么任务)
  • 而 start 才是真正调用了系统 API(应用程序接口),在系统中创建出线程,让线程再调用 run。

此上我们完成了第一个多线程,main方法对应了主线程,run方法对应了thread线程。

之后我们再稍稍复杂一下代码 ,死循环一下

可以看到这两个循环在 “同时执行 ”,两边的语句在交替打印。 

这就非常符合线程的特点 —— 每个线程都是独立执行的逻辑(都是独立的执行流) 。

程序走到 thread.start() 那里之后,兵分两路,一路继续走主线程,另一路走我们创建的新线程 

那这种执行方式就是我们前面所说的 “并发执行”,从而也就达到了 并发编程 的效果。充分的使用了多核CPU资源。

那如果我们把thread.start(), 改成thread.run() 会怎么样呢?

那此时,代码就不会创建出新的线程,只有一个主线程,那主线程只能依次执行,这个走完才能到下一步,那run()方法那里是死循环,那就有了下面的情况

  

只有hello thread 没有 hello main 

ps: 如果你想要打印的慢点,就可以利用 sleep(),(还得抛出个异常)

从上图我们可以看到,两条语句的执行顺序是不一定的,这个过程可以看成是 “随机的”

也就是说,操作系统,对于多线程的调度执行顺序,是“随机的” (这个随机和数学里的 概率均等的随机不一样,这个“随机”取决于 操作系统 对于线程调度的模块(调度器)的具体实现)

——方法2 实现 Runnable 接口

 实现 Runnable 接口,重写run(),创建 Thread 类实例, 调用 Thread 的构造方法时将 Runnable 对象作为参数,调用 start 方法

从上面的代码可以看出,和继承Thread 的写法是一样的,作用也是描述线程的入口。 

从上图看出 这个 Runnable还是要搭配 Thread 使用

Runnable本身与线程没有直接的联系,这里的Runnable 单纯的表示 “可以运行的任务”,这个任务交给线程还是其他的什么来执行,Runnable并不关心。

把这个任务放到线程里来执行,最终还是要通过thread.start(), 这个操作,调用系统的API(应用程序接口)来完成创建线程的工作。

执行情况和上边一样 

—— 使用Runnable的写法 和 直接继承 Thread 有什么区别?

三个字概况:解耦合

(ps:耦合,相互影响越大,耦合越高)

👈(⌒▽⌒)👉 解释  👈(⌒▽⌒)👉

我们要知道,创建一个线程,需要两个关键操作:

  1. 明确线程要执行的任务

—— 任务本身不一定和线程相关,这个任务只是单纯执行一段代码不管它是使用单个线程还是多个线程去执行,或者什么其他的方法,都没什么区别,此时就可以把这个任务单独 提取出来,让任务和线程解耦合,那就可以随时把代码改成其他方式来执行这个任务

    2.调出系统API(应用程序接口)创建出线程

匿名内部类 方法 

继承 Thread,重写run,但是使用匿名内部类 

 

具体如何写,如下: 

其实没什么区别,就是把方法挪了个位置。和方法一本质一样,就是换了个写法。 

实现Runnable,重写run,使用匿名内部类

一样一样 

或者更简便 

基于 lambda 表达式 【推荐 比前面的方法都简单】

lambda表达式 是一种更简化的语法表示方式。(“语法糖” )。

相当于是 “匿名内部类” 的替换写法。

—— lambda 表达式 (介绍了回调函数)

 

 lambda 表达式 ,本质上是一个匿名函数(一次性的), 主要用来实现“回调函数”的效果。

(java中不允许函数独立存在,(Java这里叫方法),所以lambda 本质是函数式接口(还是没脱离类))

 ——“回调函数”是计算机中非常重要的术语,我们来了解一下

  • 首先我们要知道 “函数指针”

       函数指针指向内存空间的,函数为什么跑到内存里了?,这背后是操作系统 加载一个可执行程序 创建进程的过程 

       我们写的代码的都是一个一个文件,都在硬盘里,然后编译,得到个.exe, 还是个文件,当双击这个.exe, 操作系统会加载这个.exe, 把.exe 里的指令和数据加载到内存中,构建成一个进程,此时我们所写的这些函数所对应的二进制指令就进入内存中了,这个时候我们才能拿指针指向它。

  • 函数指针有很多用出
  1. 使用函数指针 实现转移表,降低代码的圈复杂度(就是减少 if else 的分支数目)
  2. 使用函数指针作为 回调函数。

  ——接下来就来介绍 回调函数

回调函数与普通的函数有个最明显的特点,回调函数不是你主动调用的,也不是现在就立即调用,而是把调用的机会交给别人来使用,别人会在合适的时机调用这个函数

(ps: 这个“别人” 通常是 操作系统,库,框架,别人写的代码)

接下来我们完善一下这个代码,(和上面差不多) 

执行效果也和上面一样 

除了这些还会有一些方法,这里就先不介绍了。 

 Thread 类的其他常见使用方法
 

—— Thread 的常见构造方法
 

方法说明
Thread()创建线程对象
Thread(Runnable target)使用 Runnable 对象创建线程对象
Thread(String name)创建线程对象,并命名
Thread(Runnable target, String name)使用 Runnable 对象创建线程对象,并命名
【了解】Thread(ThreadGroup group,
Runnable target)
线程可以被用来分组管理,分好的组即为线程组,这
个目前我们了解即可
  • 这俩前面刚介绍完。


  • 接下来两个,我们看看这个 name 是干啥的。 

当创建线程的时候我们可以指定 name,name不影响线程的执行,只是给线程起个名字,方便再之后调试的时候进行区分 

代码如下: 

 

我们利用 jconsole 来看一下效果(一般再 C:\Program Files\Java\jdk1.8.0_192\bin 这个路径下)

上图清晰显示出了名字。 

—— Thread 的几个常见属性
 

属性获取方法
IDgetId()
名称getName()
状态getState()
优先级getPriority()
是否后台线程isDaemon()
是否存活isAlive()
是否被中断isInterrupted()

线程的身份标识,标识一个进程中唯一的一个线程(这个 id 是Java 给你这个线程分配的,不是系统API提供的线程id,更不是 PCB 中的id。) 

  • ⁜⁜⁜ 守护线程(后台线程)

——我们先了解一下前台线程 :

一个Java进程中,如果前台进程 没有执行结束,那此时的整个线程是 一定不会结束的,

相比之下,后台程序是否结束,不影响整个进程的结果。

因为一般情况下默认是前台线程,所以我们手动设为后台线程

运行一下,发现直接退出了,

改成后台程序之后,主线程飞快执行完了,此时没有其他前台线程,于是进程结束。 (t线程还没来得及执行呢,就完了)

Thread 对象的生命周期,要比系统内核中的线程更长一些,就会出现,Thread 对象还在,但是内核中的线程已经销毁了这样的情况

那此时就可以使用 isAlive()  来判断内核里的线程是否已经没了(回调方法执行完毕,线程就没了)

接下来用利用代码来看一下 

执行结果 

ps:小细节,true 和 线程开始 这两个日志不一定谁先打印。 因为线程是并发执行的,并发调度顺序不确定,取决于系统的调度器,(但大概率是先打印 true,因为调用 start 之后,新的线程创建也是有开销的,创建过程中,主线程就执行完了)

 启动线程-start() (含经典面试题,start 和 run的区别)

线程启动,start() 方法是最关键的方法

start 方法内部,是会调用到系统 API,来再系统内核中创建线程的,

相比之下,run方法,只是单纯的描述了该线程要执行的内容。(会在start 创建好线程之后自动被调用) 

中断线程 

interrupt (终止/打断) 

就是让一个线程停止运作(销毁)

在 Java 中,要销毁/终止线程,做法是比较唯一的,就是想办法让 run 方法尽快执行结束。

-- 方案一 

可以在代码中手动创建出标志位,来作为 run 的执行结束的条件。  

很多线程,执行时间久,往往是因为这里写了一个循环,循环持续很久导致的,要想让run执行结束,我们就要让 循环 尽快退出。 

----代码实现 

执行结果 

小问题: 

       当前这个代码,是使用了一个成员变量 isQuit 来作为标志位,如果把isQuit 改为 main 方法中的局部变量,是否可行呢??

  • 答:不可行
  • 原因:

上图可看见,当把isQuit 改为 main 方法中的局部变量时,while 那里报错了,

但是当把 isQuit = true 注释掉之后就不报错了,

所以我们就可以得知这里的关键是 不能修改。为什么? 

因为lambda 表达式,有个语法规则 —— 变量捕获,lambda 表达式里面的代码,是可以自动捕获到上层作用域中涉及到的局部变量 。

这个变量捕获可以理解为就是让 lambda 表达式,把当前作用域中的变量在lambda内部复制了一份。(所以此时如果外面是否销毁,就无所谓了)

但是,在Java中,变量捕获语法,还有一个前提限制,就是必须只能捕获一个 final(常量) 或者是实际上是 final 的变量。

——final 

 —— 实际上是 final

所以当下面修改的时候就一定会报错了 。

但当 isQuit 是成员变量时,lambda 访问这个成员时,就不是变量捕获这个语法了,

而是 ” 内部类访问外部类的属性“,没有final之类的限制。

所以不能把isQuit 改为 main 方法中的局部变量。

但上述方案,不够优雅,需要手动创建变量:还有当线程内部在 sleep 的时候,主线程修改变量,新线程内部不能及时响应。所以有了方案二。 

--  方案二

Tread 类内部 ,有一个现成的标志位  Thread.currentThread().isInterrupted(),可以用来判断当前的循环是否要结束。

——介绍  Thread.currentThread().isInterrupted()

ps: 注意不能直接使用 t.  ,因为此时t 还在构建当中 

通过  t.interrupt(),这个操作,就把上述的Thread对象的内部的标志位给设置成 true 了。

     ps:  而且使用  t.interrupt() 即使线程内部逻辑出现了堵塞(sleep)也是可以使用这个方法唤醒的.  正常来说,sleep会休眠到时间结束 才醒,但此处的interrupt就可以使 sleep 内部触发一个异常,从而被提前唤醒。

我们运行看看结果 

当代码sleep 那里的异常写成这样的时候 

我们就会发现,异常是抛出了但是线程没停止 

这是因为interrupt 唤醒线程之后,此时sleep 方法抛出异常,同时会自动清楚刚才设置的 标志位 

这样就使得 ”设置标志位“ 这个效果好像没有生效一样。

那为啥这么设置呢? 

       这是因为Java期望,当线程收到“要中断”这样的信号时,线程可以自由决定,接下来该如何处理。

    一般线程可以采取三种方式来进行操作:

     1.假装没听见,循环继续正常执行(就是上面的情况)

   2.加上一个 break ,表示让线程立即结束。 

运行效果,线程立刻就结束了。 

 3. 可以在break,前做一些其他工作,完成之后在结束

这样就让我们程序员有更多的 “可操作性空间”   (“可操作性空间” 的前提是 通过 “异常”的方式唤醒的,如果没有sleep,就没有上述的操作空间) (就是没有异常那就正常执行,有异常我们就要再确认一下,看看怎么回事)

ps: IntelliJ IDEA Community Edition 2022.3.3 这个版本的IDEA,生成的try-catch是这样的,

执行之后是可以结束的 

  

线程等待 

有时,我们需要等待一个线程完成它的工作后,才能进行下一步工作 。

本质上就是控制线程结束的顺序。

方法说明
public void join()等待线程结束
public void join(long millis)等待线程结束,最多等 millis 毫秒
public void join(long millis, int nanos)同理,但可以更高精度

“join() 方法”就是实现线程等待效果的。(在哪个线程里调用了join,哪个线程就阻塞) 

如果在主线程中,调用t.join(), 那此时就是主线程等待t 线程,等待t 线程结束。

利用代码,我们能清晰的看见join的效果。 

执行效果 

t.join 工作过程

  • 如果 t 线程正在运行,那此时调用 join 的线程就会阻塞,一直阻塞到  t 线程执行结束。
  • 如果 t 线程已经执行结束了,那此时调用 join 线程,就直接返回了,不会阻塞。
  • 如果 t 线程一直不结束,join 默认情况下是 “一直等待的”。

但是一直等待不现实,一般,等待操作都有一个“超时时间”,就有了第二个方法  

public void join(long millis)。等待线程结束,最多等 millis 毫秒。

╰(*°▽°*)╯╰(*°▽°*)╯╰(*°▽°*)╯╰(*°▽°*)╯╰(*°▽°*)╯完 ╰(*°▽°*)╯╰(*°▽°*)╯╰(*°▽°*)╯╰(*°▽°*)╯╰(*°▽°*)╯

 

   

 

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

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

相关文章

在本地搭建Jellyfin影音服务器,支持公网远程访问影音库的方法分享

文章目录 1. 前言2. Jellyfin服务网站搭建2.1. Jellyfin下载和安装2.2. Jellyfin网页测试 3.本地网页发布3.1 cpolar的安装和注册3.2 Cpolar云端设置3.3 Cpolar本地设置 4.公网访问测试5. 结语 1. 前言 随着移动智能设备的普及,各种各样的使用需求也被开发出来&…

prometheus+cadvisor监控docker容器

一、安装cadvisor docker pull google/cadvisor:latest二、运行容器 docker run -d \--volume/:/rootfs:ro \--volume/var/run:/var/run:rw \--volume/sys:/sys:ro \--volume/var/lib/docker/:/var/lib/docker:ro \--publish8088:8080 \--detachtrue \--namecadvisor \--priv…

解释基本的3D理论

推荐:使用 NSDT场景编辑器 快速搭建3D应用场景 坐标系 3D 本质上是关于 3D 空间中形状的表示,并使用坐标系来计算它们的位置。 WebGL 使用右侧坐标系 — 轴指向右侧,轴指向上方,轴指向屏幕外,如上图所示。xyz 对象 …

Linux之Shell(一)

Linux之Shell Shell概述Linux提供的Shell解析器bash和sh的关系Centos默认的解析器是bash Shell脚本入门脚本格式第一个脚本脚本常用的执行方式 变量系统预定义变量自定义变量特殊变量$n$#\$*、\$$? 运算符条件判断流程控制(▲)if判断case语句for循环while循环 read读取控制台输…

[SpringBoot3]远程访问@HttpExchange

六、远程访问HttpExchange[SpringBoot3] 远程访问是开发的常用技术,一个应用能够访问其他应用的功能。SpringBoot提供了多种远程访问的技术。基于HTTP协议的远程访问是最广泛的。SpringBoot中定义接口提供HTTP服务。生成的代理对象实现此接口,代理对象实…

matlab使用教程(26)—常微分方程的求解

1.求解非刚性 ODE 本页包含两个使用 ode45 来求解非刚性常微分方程的示例。MATLAB 提供几个非刚性 ODE 求解器。 • ode45 • ode23 • ode78 • ode89 • ode113 对于大多数非刚性问题,ode45 的性能最佳。但对于允许较宽松的误差容限或刚度适中的问题&…

最大子数组和【贪心算法】

最大子数组和 给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 子数组 是数组中的一个连续部分。 class Solution {public int maxSubArray(int[] nums) {//记录最大结果&…

HarmonyOS扫码服务,应用服务一扫直达打造系统级流量新入口

二维码如今是移动应用流量入口以及功能实现的重要工具,也是各App的流量入口,是物、人、服务的连接器,通过扫码我们可以更便捷的生活,更高效的进行信息交互,包括信息的发布、信息的获取。 在日常扫码过程中&#xff0c…

Matlab(基本操作与矩阵输入)

目录 1.Matlab视窗详读 2.基本操作与矩阵输入 2.1 运算符的优先级 2.2 初等数学函数 2.3 嵌入函数 2.4 特殊变量和常量 2.5 Matlab的优先级调用 2.6 数字显示格式长 2.7 命令行中端 2.8 部分函数 2.9 向量和矩阵 2.10 数组索引 2.11 串联矩阵 2.12 生成数值序列 …

智慧景区方案:AI与视频融合技术如何助力景区监管智能化升级?

随着经济的发展,人们对生活的需求也不再局限于温饱层面,越来越多的人们开始追求文化、艺术的高层次需求,旅游也逐渐成为人们日常放松的一种方式。由于我国人口多、易扎堆等特点,景区的运营监管方式也亟需改革。TSINGSEE青犀智能分…

优维产品最佳实践第5期:什么是持续集成?

谈到到DevOps,持续交付流水线是绕不开的一个话题,相对于其他实践,通过流水线来实现快速高质量的交付价值是相对能快速见效的,特别对于开发测试人员,能够获得实实在在的收益。 本期EasyOps产品使用最佳实践&#xff0c…

Android学习之路(11) ActionBar与ToolBar的使用

自android5.0开始,AppCompatActivity代替ActionBarActivity,而且ToolBar也代替了ActionBar,下面就是ActionBar和ToolBar的使用 ActionBar 1、截图 2、使用 2.1、AppCompatActivity和其对应的Theme AppCompatActivity使用的是v7的ActionBa…

【C语言】指针 和 数组 笔试题详解

目录 一、数组 1.一维数组 2.字符数组 3.二维数组 二、指针 笔试题1 笔试题2 笔试题3 笔试题4 笔试题5 笔试题6 笔试题7 笔试题8(有难度)【看明白会有质的收获】 在这里我们需要先了解数组名的意义 sizeof(数组名) ,这里的数组名表示…

《用行动打造满意的服务》考试答案

中电金信新员工入职培训选修课程《用行动打造满意的服务》考试答案

Mysql高级语句

高级语句 1.按关键字排序 SELECT column1, column2, ... FROM table_name ORDER BY column1, column2, ... ASC|DESC ASC 是按照升序进行排序的,是默认的排序方式,即 ASC 可以省略。 SELECT 语句中如果没有指定具体的排序方式,则默认按 ASC…

[论文笔记]DSSM

引言 这是DSSM论文的阅读笔记,后续会有一篇文章来复现它并在中文数据集上验证效果。 本文的标题翻译过来就是利用点击数据学习网页搜索中深层结构化语义模型,这篇论文被归类为信息检索,但也可以用来做文本匹配。 这是一篇经典的工作,在DSSM之前,通常使用传统机器学习的…

Java“魂牵”京东商品详情描述数据,京东商品详情API接口,京东API接口申请指南

要通过京东的API获取商品详情描述数据,您可以使用京东开放平台提供的接口来实现。以下是一种使用Java编程语言实现的示例,展示如何通过京东开放平台API获取商品详情: 首先,确保您已注册成为京东开放平台的开发者,并创…

ACM模式数组构建二叉树Go语言实现

目的 想输入一个数组,然后构造二叉树 例如数组为[6, 2, 8, 0, 4, 7, 9, -1, -1, 3, 5] 对应的二叉树为: 参考资料 ACM模式数组构建二叉树 重点:如果父节点的数组下标是i,那么它的左孩子下标就是i*21,右孩子下标就是…

持续加码,科士达重仓储能!

储能的热度,如温度计一样真实展现在各种数据榜单上:新注册企业的数量,转型跨界的企业,尤其IPO募资扩产规模,更是成为了储能企业竞赛的新标准。 日前,科士达一则新的定向募资预案,吸引了业内广泛…

C++-list实现相关细节和问题

前言:C中的最后一个容器就是list,list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指…