百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术流 > 正文

多线程编程引子:进程、线程、线程同步

citgpt 2024-08-01 13:31 11 浏览 0 评论

前言

最近在总结《Java多线程编程核心技术》这本书。实话实说:多线程编程核心技术,这些字眼属实有些夸大。

但是也不能因为此,就直接否认了书籍本身的价值。这是一篇比较适合入门阅读的书籍。和我最近在尝试写的文章有相似之处,也就是尽力让知识点,少思考性而多阅读性。

多线程编程引子:进程、线程、线程同步

因此接下来会将这本书的内容,揉到我的接下来的文章中,旨在:真正能在碎片化时代下,进行有效学习。

正文

毫无疑问,一切的开始。肯定是先介绍介绍概念性的东西。主题是线程,但是谈到线程,势必不能忘了进程。因此让我们先来聊一聊线程和进程的概念。

接下来让我们有请文章一贯的主角:小AMDove出场~

进程和线程

小A:MDove,我最近在思考一个问题,多线程多线程。那到底什么是多线程呢?

MDove:想要理解多线程,其实就要不得不提一提:进程,以及进程和线程之间的关系。

一个比较通俗且常见的解释:进程:操作系统分配资源的基本单位;线程:操作系统调度最小单位。

稍稍学院派的解释:

来自《现在操作系统(第4版)》 + 维基百科 + 百度百科

进程:

  • 进程的本质是正在执行的一个程序,进程基本上上容纳运行一个程序所需要的所有信息的容器。
  • 在当代多数操作系统中,进程本身不是基本运行单位,而是线程的容器。程序本身只是指令、数据及其组织形式的描述,进程才是程序的真正运行实例。
  • 早期面向进程设计的计算机结构中,进程是系统进行资源分配和调度的基本单位。

小A:哦?既然进程是程序的实体,那么只要进程不就行了?

MDove:这当然是没有问题啦。但是,一个致命的问题,大家都追求快,更快,非常快!

小A:不不不不不,我就追求慢,坚挺~

MDove:坚挺是吧,你这么秀,你怎么不去Tokyo Hot?搁这给我扯犊子。学不学了?不学你去找加藤鹰去。

小A:学学学,我的理解:是不是线程比进程占用资源更少?

MDove:其实关于消耗资源这个问题很难回答。比如Linux、Windows对进程和线程的设计就是不同的。如果从Linux的角度出发,进程和线程无论是创建还是上下文切换其实不在极端情况下,所谓的性能还是资源,差距并不是很大。差距比较大的一点是:进程是内存独立,而线程内存共享。

MDove:当然,二者都可以悄摸得去做一些事情,但不同点在于:进程间通讯,远比线程间通讯复杂的。因此在上层高级语言的设计上,线程便成了不错的用于后台完成耗时操作的一个工具。但是不可否认的一点,多进程同样扮演者举足轻重的角色!打个比方,单进程的程序,如果杀死这个进程那么这个进程所依附的所有线程全部死亡。而多进程则不怕,毕竟彼此是独立运行的进程,因此多进程在拉活方面有着不俗的战斗力。

小A:哦~原来如此,那可以聊一聊线程么?

MDove:好的,接下来让我们看一看线程。


线程:

  • 是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
  • 线程可以为操作系统内核调度的内核线程;由用户进程自行调度的用户线程

MDove:举个小例子:打开我们计算机上的任务管理器时,进程Tab页上,我们看到的就是进程;而独立进程程序的子任务就是线程(不绝对,也可以存在多进程的程序)。比如:QQ运行时(进程),就有很多子任务(线程)在同时运行:你即能一遍和基友视频,一遍还能和其他基友文字聊天这就体现了多线程,其中每一项子任务都可以理解为线程

MDove:对于我们开发者来说线程是一个很常见的概念。对于Java后台来说,能够熟练的掌握对多线程的使用。可以说是掌握核心科技一样。

小A:???听你这么说,多线程没什么难的呀?

多线程的弊端

MDove:初生牛犊不怕虎,但你要明白,虎终究是虎。多线程的一大难点在于线程安全问题。因为内存共享的原因,导致了线程刷新内存的滞后性。

小A:???什么意思???

MDove:打个比方,在Java线程模型中:每个线程运行时,都会把主内存中的变量值复制到自己的工作内存当中,当自己执行完毕后,在把计算完毕的工作内存中的变量,反过来赋值给主内存。

小A:嗯?这好像没什么问题啊?

MDove:没问题?问题大了去了!咱们举一个花钱的例子:现在咱们账本上有十个亿。你是一个线程,我是一个线程。

  • 我先执行了,我拿了一个亿,去建设了一下社会主义核心价值观,然后我在我的账本里记了一下账:我拿了1个亿,手头还有9个亿

此时咱们的账本还剩9个亿

  • 接下来,你也出动了,你拿了9个亿中的一个亿,你也在你的账本里记了一下账:我拿了1个亿,还有8个亿。然后你去吸烟喝酒烫头了。

此时咱们的账本还剩8个亿

  • 这个时候我干完了我的事,我花了5千万,还剩5千万。然后对于我来说我的账本变成了,还有9亿5千万。此时我把我的账本写到了咱们们公共账本里…

小A:等会等会?你想啥呢?钱越花越多了!我都拿走1个亿了,你那咋还9个亿呢?你就不会同步一个我的账本么?

MDove:没错呀,我就不会同步一个你的账本呀!这就是多线程的问题所以。因为每个线程是独立运行的,谁都不管谁,因此,如何同步线程之间的数据便成了至关重要的一点!

小A:这么一说我就明白了,那怎么同步呢?

保证线程安全

可见性,原子性

MDove:其实刚才的问题就出现在账本的不同步上,因此如果我们能够解决账本的同步问题,理论上就可以解决咱们的线程安全问题。当然你可以用一些手段通知我,让我更新我的账本(可见性)。但是仍存在问题,如果我们写账本的操作是个多步骤的复杂操作,可能就会存在问题了,因为这个里每一步通存在同步问题,只有当我们的写账本操作是一个单一操作(原子性)那么这种做法就是没有问题的。

小A:局限还挺多,那有没有其他方式呢?

加锁

MDove:接下来说一个加锁的方式。举个咱们上厕所的例子。我们很多人都要上厕所,如果我们的厕所没有任何措施,那么画面简直无法想象。因此,咱们…那啥…大号…的时候,都会把门锁上。其他人一看门锁上了,也就只好默默的憋一会。

MDove:当我们解决后,打开门,其他人就可以尽情释放了。

那么这个过程就相当于:一个线程在操作一个变量时,直接把这个变量锁起来。其他线程只能等着,因此肯定就不会存在多个线程同时操作变量的问题了。

线程优先级

小A:那么接下来就是队伍中第一个人去…那啥么?

MDove:当然不是,线程的世界可没有什么先来后到。而是按线程的优先级去排列。那么如果没有优先级,那就看谁的拳头更硬谁的运气更好了。

小A:好残暴,那有没有顺利排列的可能性呢?那我们可不可以自己固定一个顺序去开启线程的执行呢?

线程执行顺序

MDove:我们当然可以指定一种策略去顺序的start我们的线程,但是我们只能保证线程start的顺序,没办法保证线程调度的顺序。因为对于线程来说,什么时候能够获得操作系统的宠幸那是不确定的。因此线程会有多种状态:

  • 新建(NEW),表示线程被创建出来还没真正启动的状态。
  • 就绪(RUNNABLE),表示该线程已经在 JVM 中执行,当然由于执行需要计算资源,它可能是正在运行,也可能还在等待系统分配给它 CPU 片段,在就绪队列里面排队。
  • 阻塞(BLOCKED),阻塞表示线程在等待锁释放。比如,线程试图去获取某个锁,但是其他线程已经独占了,那么当前线程就会处于阻塞状态。
  • 等待(WAITING),表示正在等待其他线程采取某些操作。。
  • 终止(TERMINATED),不管是意外退出还是正常执行结束,线程已经完成使命,终止运行。

当然也可以加上一个:运行(RUNNING):可运行状态(RUNNABLE)的线程获得了CPU时间片,开始执行代码。

分段锁

MDove:咱们再回到那个厕所的例子。我们日常中…厕所肯定不止一个坑位,一般会有好几个。毕竟都是解决同样的问题,没有只设置一个坑位的道理。

MDove:所以对于我们程序来说也是如此,在面对类型的场景也会有类似的实现,这个方式就叫做分段锁。比如:ConcurrentHashMap,JDK1.8版本之前的设计。

MDove:当然关于锁这个话题,其实水是很深的。我们嘚吧嘚说了这么多,其实就是在解决多线程安全问题。因此明白了吧,多线程是一个值得深入学习的内容。

小A:学的我热血沸腾的,接下来教教我,Java中对线程的使用吧!

MDove:别急,聊了这么久厕所的话题,容我上个厕所,咱们下期再来聊一聊线程的使用。

剧终

相关推荐

js中arguments详解

一、简介了解arguments这个对象之前先来认识一下javascript的一些功能:其实Javascript并没有重载函数的功能,但是Arguments对象能够模拟重载。Javascrip中每个函数...

firewall-cmd 常用命令

目录firewalldzone说明firewallzone内容说明firewall-cmd常用参数firewall-cmd常用命令常用命令 回到顶部firewalldzone...

epel-release 是什么

EPEL-release(ExtraPackagesforEnterpriseLinux)是一个软件仓库,它为企业级Linux发行版(如CentOS、RHEL等)提供额外的软件包。以下是关于E...

FullGC详解  什么是 JVM 的 GC
FullGC详解 什么是 JVM 的 GC

前言:背景:一、什么是JVM的GC?JVM(JavaVirtualMachine)。JVM是Java程序的虚拟机,是一种实现Java语言的解...

2024-10-26 08:50 citgpt

使用Spire.Doc组件利用模板导出Word文档
  • 使用Spire.Doc组件利用模板导出Word文档
  • 使用Spire.Doc组件利用模板导出Word文档
  • 使用Spire.Doc组件利用模板导出Word文档
  • 使用Spire.Doc组件利用模板导出Word文档
跨域(CrossOrigin)

1.介绍  1)跨域问题:跨域问题是在网络中,当一个网络的运行脚本(通常时JavaScript)试图访问另一个网络的资源时,如果这两个网络的端口、协议和域名不一致时就会出现跨域问题。    通俗讲...

微服务架构和分布式架构的区别

1、含义不同微服务架构:微服务架构风格是一种将一个单一应用程序开发为一组小型服务的方法,每个服务运行在自己的进程中,服务间通信采用轻量级通信机制(通常用HTTP资源API)。这些服务围绕业务能力构建并...

深入理解与应用CSS clip-path 属性
深入理解与应用CSS clip-path 属性

clip-pathclip-path是什么clip-path 是一个CSS属性,允许开发者创建一个剪切区域,从而决定元素的哪些部分可见,哪些部分会被隐...

2024-10-25 11:51 citgpt

HCNP Routing&Switching之OSPF LSA类型(二)
  • HCNP Routing&Switching之OSPF LSA类型(二)
  • HCNP Routing&Switching之OSPF LSA类型(二)
  • HCNP Routing&Switching之OSPF LSA类型(二)
  • HCNP Routing&Switching之OSPF LSA类型(二)
Redis和Memcached的区别详解
  • Redis和Memcached的区别详解
  • Redis和Memcached的区别详解
  • Redis和Memcached的区别详解
  • Redis和Memcached的区别详解
Request.ServerVariables 大全

Request.ServerVariables("Url")返回服务器地址Request.ServerVariables("Path_Info")客户端提供的路...

python操作Kafka

目录一、python操作kafka1.python使用kafka生产者2.python使用kafka消费者3.使用docker中的kafka二、python操作kafka细...

Runtime.getRuntime().exec详解

Runtime.getRuntime().exec详解概述Runtime.getRuntime().exec用于调用外部可执行程序或系统命令,并重定向外部程序的标准输入、标准输出和标准错误到缓冲池。...

promise.all详解 promise.all是干什么的
promise.all详解 promise.all是干什么的

promise.all详解promise.all中所有的请求成功了,走.then(),在.then()中能得到一个数组,数组中是每个请求resolve抛出的结果...

2024-10-24 16:21 citgpt

Content-Length和Transfer-Encoding详解
  • Content-Length和Transfer-Encoding详解
  • Content-Length和Transfer-Encoding详解
  • Content-Length和Transfer-Encoding详解
  • Content-Length和Transfer-Encoding详解

取消回复欢迎 发表评论: