线程初步理解

线程初步理解

一、线程

  线程会共享进程范围内的资源,同时,每个线程也会有各自的程序计数器,栈,以及了局部变量。

  线程有效降低了程序开发、维护成本,提升了复杂应用程序的性能,让系统可以更好地利用计算机资源,提高系统的处理能力,为用户界面提供更加灵敏的响应。

二、多线程的危险

  1. 安全性问题 :在多个线程不完全同步的情况下,多个线程执行的顺序是不可预测的,那么不同的执行顺序就可能带来极其糟糕的结果。
  2. 活跃性问题 :活跃性问题关注“某件正确的事情是否最终会发生”,有时候因为线程之间的相互等待,或者单线程的无限循环问题,就会引发活跃性问题。
  3. 性能问题 :线程总会带来额外的运营开销,如果这些开销过于大,会直接影响到系统的性能。

三、线程安全类

  • 定义
      如何定义一个类是线程安全的呢?最核心的问题在于正确性,在代码中无需进行额外的同步或者协同操作的情况下,无论有多少个线程使用这个类,无论环境以何种方式调度多线程,这个类总能表现出正确的行为,我们就成这个类是线程安全的。

  • 无状态的对象一定是线程安全的
      因为无状态的线程不会影响到其他线程的状态,这个线程中的操作并不会影响到其他线程的执行,所以无状态的对象一定是线程安全的。

  • 当一个无状态的对象增加一个状态时,如果这个状态完全有线程安全的对象来管理,那么原来这个对象仍然是线程安全的。

四、竞争状态和竞争条件

  • 竞争状态
      在并发编程中,由于不恰当的执行时序而导致的结果的错误,这种情况叫做竞争状态

  • 竞争条件
      引发竞争状态的条件就是竞争状态的竞争条件

  • 原子操作
      原子操作即指某动作要不不完成,要不一次性完成,中间不会被打断或者干扰

  • 竞争条件“先检查后执行”
      "先检查后执行"是最常见的一种竞争条件。”先检查后执行”即先进行检查某状态,然后根据这种状态来决定下面发生的动作,这种方式不具有原子性,那么这种依赖的状态就可能在动作发生之前发生变化,最终导致结果的错误。总结来说,“先检查后执行”依赖的是不可靠的状态条件,因为可能会发生错误。

五、解决竞争状态

1.单状态情况-使用java.util.concurrent.atomic下的原子变量

  • 这些原子变量的增加减少等运算都可以保持原子性,那么就会保证某个状态是线程安全的。

2.复合状态的情况

  • 如果再使用第一种方法,虽然多个变量各自可以保持线程安全,但是多个变量之间的协同不是原子的操作。例如a变量和b变量有某种联系,a和b需要做同步的修改,那么修改的操作也必须是原子操作。因而第一种方法就失效了。
  • Java提供了一种内置锁的机制:同步代码块(Synchronized Block),这种机制可以保证某个过程是原子操作,从而保证了线程安全。

六、Java内置锁

1.同步代码块(Synchronized Block)

  1. Java的同步代码块有两部分组成,一部分是由锁保护的代码块,另一部分是锁的对象。
    • 以synchronized修饰的方法就是由锁保护的代码块。
    • 这个方法所在的对象就是这个锁,静态方法的话,方法所在的class就是锁。
  2. 重入
    • Java内置锁是可以重入的,即同一线程可以对自己持有的锁进行反复的进入。实现方法是:锁是有计数器和持有者这两个变量,计数器默认为0,持有者为空,当有人访问锁时候,JVM会自增计数器,并且将持有者设置为锁的对象,只有当同一个线程再次访问这个锁的时候,线程还可以获得这个锁,并且计数器增加;退出后,释放锁,计数器减少。
  3. 同步代码块可能来性能问题,因为多个线程只能有一个来执行被锁定的方法,其他处于等待的过程,会出现性能缺失。
原文地址:https://www.cnblogs.com/yanwenxiong/p/7376385.html