秒懂Java并发和线程安全

背景

在平时写代码的时候我们经常会说“这会不会有线程安全问题,是不是得加把锁呢?”,细细的品一下这句话,是包涵很多知识点在里面。线程?,线程安全?,什么时候才会出现线程安全?Java中的锁? 等等。

知识点

什么是线程?

  1. ”线程是承载代码运行的载体“ 这是我脑子里飘出来的第一句话。
  2. 看看WIKI百科是如何讲的: 线程(英语:thread)是操作系统能够进行运算调度的最小单位。大部分情况下,它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。在Unix System V及SunOS中也被称为轻量进程(lightweight processes),但轻量进程更多指内核线程(kernel thread),而把用户线程(user thread)称为线程。
  3. 好像我说的也没什么毛病,再具体总结一下“线程是操作系统调度程序执行的最小单位,线程是包含在进程里的,一个进程可以包含多个线程”。

什么是线程的并发和并行

  1. 并发 : 指在某个时间段内,多个任务交替处理的能力。每个CPU不可能只顾着执行某一个线程,而不管其他线程,导致其他线程一直处于等待状态。所以CPU把可执行的时间片段 均匀的分为若干份,每个线程执行一段时间后,记录当前的工作状态,释放相关的执行资源并进入等待状态,让其他线程抢占CPU资源。
  2. 并行:并行是指同时处理多任务的能力,比如多个CPU同时执行多个任务。
    其实我们也可以举个列子: KTV唱歌的时候一个话筒,一首歌,被大家轮流使用去唱,就是并发(只不过这个多成很快,完全柑桔不到),多个人同时去唱就是并行。
  3. Java中一个线程“朝生夕死”的过程
    在这里插入图片描述
    • 创建一个线程:有三种方法,1. 继承Thread的类 2.实现Runable接口 3.实现Callable接口
    • 调用我们继承或实现接口的方法调用start方法启动线程,此时线程处于就绪状态(RUNABLE)这个时候线程被再一次调用会跑出异常。
    • 接下来如果顺利的话会进入执行状态(RUNNING),也就是run()方法被执行。但是不顺利的话就会属于阻塞状态。
    • 进入阻塞状态有这几种方式:
      1. 同步阻塞:锁被其他线程占用,
      2. 主动阻塞: 调用Thread方法主动让出CPU的执行权,比如sleep(),join()等
      3. 等待阻塞: 执行了wait()
    • 终止状态(DEAD),run()执行结束,或者因异常推出后的状态,此状态不可逆转。
  4. 在并发环境下会导致哪些问题呢?
    • 那就是在线程之间操作一个共享变量的时候会出现程序预期之外的结果。这也就是线程的安全问题
    • WIKI对线程安全的描述:“线程安全是程式设计中的术语,指某个函数、函数库在多线程环境中被调用时,能够正确地处理多个线程之间的共享变量,使程序功能正确完成。”

如何保证线程安全呢?

  1. 数据单线程内可见。单线程总是安全的。因为你只针对这个线程可见那么其他的线程对此参数做不了更改了。在我们平时在方法内定义的变量也就是局部变量,他就是安全的,局部变量会被存储在独立的虚拟机栈中的局部变量表中,虚拟机栈是在线程的私有区。所以与其他的线程是没有关联的。
  2. 只读对象。那就是被定义为final的对象,且内部属性也得被定义为final不可变,一个对象被final修饰只是这个引用不会改变,但是内部的数据是可以改变的。所以内部属性也得被final修饰。如String,Integer等
    在这里插入图片描述
  3. 线程安全类。currentHashMap,HashTable,StringBuffer等买这些都是线程安全类其中内部方法都被加锁了。下图shihashTable的get方法 。currentHashMap采用的是分段锁hashTable的升级版。
    在这里插入图片描述
  4. 同步与锁机制。如果想要对某个对象进行并发操作,但是又不属于上述三类,那么我们开发就得自己去控制了,也是和他们类似的方式,让操作这个对象通过锁的方式同步执行。我们在日常开发中熟知的锁有两个
    • JUC 包中的sychronized,可重入锁,支持公平锁和公平锁。其内部实现是通过JUC包中的AQS,但是AQS中也使用到了JVM 的锁Sychronized。
    • sychronized关键字是JVM底层实现的锁,在每一个对象都会有一个对象头,其中对象头中有几个字节专门表示对象的锁状态,在JDK1.6之前sychronized还是一个比较重量极的锁,但是后续进行了优化,就是锁拥有了几个状态,自旋锁,轻量级锁,重量级锁。使其效率提高了起来,且sychronized是非公平锁。

总结

  • 主要还是介绍了并发和Java中的线程,并发的概念,线程通过获取CPU的时间便进行交替执行的过程成为并发。并行就是真正的同时去执行几个线程。
  • 并发操作导致线程的安全问题,多个线程并发操作一个数据,导致数据出现程序执行意料之外的情况。
  • 防止线程安全的方式和现有方法或类。也就是两点“要么只读”和“要么加锁”。
  • 明天更新锁两把锁“sychronized”,“sychronized”的详细情况

思考

通过反射机制或字节码操纵技术会将不变的对象变化掉吗?

猜你喜欢

转载自blog.csdn.net/weixin_40413961/article/details/106369400