当前位置:   article > 正文

springboot2 多线程写入数据_从一个小例子再次品位多线程

springboot谁用多线程从数据库读取数据写入文件中保证顺序

点击上方的终端研发部,右上角选择“设为星标

每日早9点半,技术文章准时送上

公众号后台回复“学习”,获取作者独家秘制精品资料

e0605060a96a02211eb12594ecb54b41.png

往期文章

记五月的一个Android面试经

今日头条屏幕适配方案落地研究

APK瘦身-是时候给App进行减负了

浅谈final、finally、finalize有什么不同?

e0605060a96a02211eb12594ecb54b41.png

本文来源:hsm_computer

原文链接:https://www.jianshu.com/p/f1a24c4b8d4a

今天回味 volatile 时看到了别人的一个 Demo:

135b6a25b8722d2aae4e1a3ae571b210.png

426957028ab3782aaf76e1e55d91c0e0.png

并发没有 volatile 的表现

读取和写入操作中的 Flag 没用 volatile 标记,这时大家猜猜线程会怎么运行,这个例子当初有人 用来解释 volatile 的内存可见性,说 thread2 栈帧中的内存副本不会同步更新,即便 thread1 修改了 flag 的值,thread2 也会一直卡在这个循环里出不来。但是…重点是但是,这是不对的,thread2 还是能结束的,只是每次 thread2 每次表现都不一样,谁也不知道 thread2 在刷新 flag 数据之前会运行多少次

我们多运行几次,看看打印情况

5624e7c005c170124e9b548c18e40c10.png

b2a1cbc0bc3701e6971f9bb8f3565e22.png

eae62a50b081b78c23a462cc21df6476.png

结果完全超出我们认知啊,这运行起来完全没有规律可言,明明我们没用 volatile 标记 flag ,但是为什么图1、图3 这么像 volatile 啊,但是图2缺不是,这怎么理解,这就要盘盘 JVM 工作内存和主内存了

JVM 工作内存和主内存

212e09ff4df2c1d701292d8406fde814.png

JVM 把内存分割为:主内存 | 工作内存 2个部分:
  • 主内存 - 堆内存和本地方法区

  • 工作内存 - 每个线程都有一个工作内存,工作内存中主要包括两个部分,一个是属于该线程私有的栈和对主存部分变量拷贝的寄存器(包括程序计数器PC和cup工作的高速缓存区)

每条线程都有自己的工作内存,工作内存中保存的是主存中某些变量的拷贝,线程对变量的所有操作都必须在工作内存中进行,而不能直接读写主内存中的变量,线程之间无法直接访问对方的工作内存中的变量,线程间变量的传递均需要通过主内存来完成

JVM规范定义了线程对内存间交互操作:

Lock(锁定)- 作用于主内存中的变量,把一个变量标识为一条线程独占的状态。

Read(读取) - 作用于主内存中的变量,把一个变量的值从主内存传输到线程的工作内存中。

Load(加载) - 作用于工作内存中的变量,把read操作从主内存中得到的变量的值放入工作内存的变量副本中

Use(使用) - 作用于工作内存中的变量,把工作内存中一个变量的值传递给执行引擎。

Assign(赋值) - 作用于工作内存中的变量,把一个从执行引擎接收到的值赋值给工作内存中的变量。

Store(存储) - 作用于工作内存中的变量,把工作内存中的一个变量的值传送到主内存中。

Write(写入) - 作用于主内存中的变量,把store操作从工作内存中得到的变量的值放入主内存的变量中。

Unlock(解锁) - 作用于主内存中的变量,把一个处于锁定状态的变量释放出来,之后可被其它线程锁定。

是不是有点看的眼花缭乱啦,仔细看这些其实都是顺序执行的操作,很好理解,知道就可,同样这些操作有自己的特性:

read - load,store - write 都是成对进行的,不允许单一出现使用
不允许线程丢弃它最近的一个 assign 操作,即变量在工作内存被更改后必须同步改更改回主内存

工作内存中的变量在没有执行过 assign 操作时,不允许无意义的同步回主内存

多线程并发的核心其实就是对于资源的可见性和有序性的处理

可见性 - 对于可见性来说,什么时候把线程工作内存中的变量副本同步到主内存中完全是 JVM 自己实现系统决定的,我找了好多资料也没有明确说明的,更具上面例子的测试,我发现有时候对数据的修改会马上同步到主内存,有时候要等到线程上下文切换时才会更新数据。另外再说一点,使用 volatile 同样也会由工作内存的问题,区别是工作内存中的修改会马上立即同步到主内存

有序性 - 有序性这个大家应该都门清,就是严格保证代码按照我们的逻辑执行,上面的例子就是个反面典型,执行成啥样我们完全控制不了

通过上面这个例子,就明明白白带出了多线程我们关心什么,多个线程同时对相同资源的使用,只要我们的代码中类似上面要处理相同的资源,那么我们必须要采用合适的多线程测量,否则执行成啥样谁知道

并发添加 volatile 的表现

还是上面的代码,我们给 flag 加上 volatile

046d7d9521015244e4b2c75fabd9fc63.png

然后我们看看运行情况:

4f22bd8166901d7336b091fd91eac94f.png

不管点几次都是读取先完事,然后再试写入完事,这样的确是保证了内存可见了,我们在任何地方修改一个 Volatile 的变量,所有改变量的副本都会立马相应,可以看到影响的速度是很快的,快的写入都来不急执行下面的任务,读取那边就完成同步了

但是从结果上看光是有 Volatile 还是不行的,逻辑上读取操作结束应该在写入完成之后执行的,这样看来 Volatile 并不能解决根本问题,还是得 Synchronized

很多人都说用 Volatile 做多线程同步必须小心再小心,通过这一个小小的例子就很明显了,Volatile 的缺陷太大,无法保证连续性和逻辑性,Volatile 最适合的场景就是赋值操作了,典型的就是单例了对吧,这个大家都知道

并发添加 Synchronized 的表现

那么写到这就完事了吗,还没有,最常用的多线程同步手段 Synchronized 我们还没用呢,既然上面 volatile 保证不了连续性逻辑性,那么我们来看看 Synchronized ,我们给写入和读取方法都改成 Synchronized 的

2855356a8dc1163c550d801a3a271757.png

但是结果呢,thread2 真的卡在这里了,thread2 拿到锁一直运行不释放锁,thread1 怎么由机会执行呢,就会想下面 log 输出一样,一直跑停不下来

29a5848a53f8cb090c1878d5c29ff8a5.png

并发 volatile + Synchronized 的表现

我们继续修改代码

f8e34ef8d1b6a42343e8cfc03d7c3237.png

是不是有人对此很期待啊,肯定有人听说过多线程使用 volatile + Synchronized 来做,但是结果吧和上面单独使用 Synchronized 一样,thread2 一直运行,thread1 没有执行的机会,可见多线程设计的复杂性,你这边的逻辑说不准就会这样。不要迷信网上有人说的 volatile + Synchronized 万能论调,存扯淡

那我们应该怎么办,显然这种单单依靠 flag 在多线程中异常危险

1、常规方式 - 我们可以放弃这个 flag 标记,完全使用 Synchronized 来实现同步,但是 Synchronized 由局限性,Synchronized 修饰的是整个方法,只能同步整个方法的执行,而不能在方法执行的过程中进行操作

2、自由加锁 - 若是我们需要在方法中根据情况不筒进行不同的同步操作,那么就剩下自己加锁这种选择了,这样可以实现更精细的操作

并发 ReentrantLock+ Condition的表现

没啥说的直接看代码

8308f2c5df25cc2c1b88bf44e4cd8d07.png

bd9f8a6235f7aac12b2f4d7cf9769dd4.png

bb781d39d9948e633ecb13118d338c1b.png

这里我们还是基于 flag 标记进行逻辑操作,所以 flag 还是要设计成 Volatile 的,然后我们自己加锁,自己阻塞,自己唤醒,阻塞的代码在被唤醒的地方继续执行,这样整个逻辑我们恩那个完全按照自己的思路去做

总结&感想

volatile 好久之前就看过了,这次精研多线程时又看了看当初的文章,于是又看到了这个小例子,看过之后马上反应过来由问题,左想不对,右也不对,谁说线程有自己的工作内存,核心标记也不是 volatile 可见的,但是 Thread2 是循环不挺的执行,不可能内存一直不刷新的,只是执行时间长短的问题,索性我把这个例子好号走走得了

然后连带着想了很多问题,比如线程工作内存何时同步到主内存,多线程的几种手段都是为了达到什么目的,意义,优势,缺陷?我是挨个试了个遍,还真是实践见真章,自己掠过这么一遍之后感觉多线程的手段在脑海里彻底清晰起来,写文章的意义也是在这里

更多相关简历的参考:

面试官:你说一下对线程安全了解多少?

Java中的Volatile到底有多难?

阅读更多

这样写简历,offer不给你给谁?

除了敲代码,你还有什么副业吗?

上两个月,15家面试,几个offer , 我的面试历程!

高仿Android「填空题」控件!手撸一个炫酷的View动效

相信自己,没有做不到的,只有想不到的

在这里获得的不仅仅是技术!

9a00c7807067c32a9f35053c44783afb.png

8323337d1707066ae5b24adb0b3e4304.gif

喜欢就给个“在看” c23bb9cd7dbafed55939bd571e65c7a1.gif

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/376240
推荐阅读
  

闽ICP备14008679号