学习Java多线程编程前必须要掌握的概念

Java是一种多线程编程语言,我们可以使用Java来开发多线程程序。 多线程程序包含两个或多个可同时运行的部分,每个部分可以同时处理不同的任务,从而能更好地利用可用资源,特别是当您的计算机有多个CPU时。多线程使您能够写入多个活动,可以在同一程序中同时进行操作处理。
但是初学者在学习java多线程的的时候,肯定会遇到肯多坑和坎,为了避免由于缺少这些基础知识给学习java多线程带来的学习障碍,甚至打击学习java的积极性,下面这些铺垫知识可以给学习java多线程带来更好的学习体验。
基础概念

  • 同步(Synchronous)和异步(Asynchronous)
    • 同步
      同步和异步通常用来形容方法调用,当调用者调用一次方法后,调用者必须等到调用方法返回,才能执行后续的行为
    • 异步
      调用者调用方法后,方法直接返回,调用者继续执行后续的行为,待异步调用完成时会通知调用者
【学习Java多线程编程前必须要掌握的概念】为了更好的解释同步和异步,再用一个例子解释一下同步和异步,假设你正在烧一壶水,同步代表的含义就是:你在烧水的时候,你必须等待烧水的任务,完成之后再去做其他事情。而异步代表的含义是:你在烧水的时候,你完全可以去干自己的事情,比如看电视,洗衣服,打电话等,当水烧好的时候,水壶会通过鸣笛的方式主动告知你水已经烧好了。
  • 并发(Concurrency)和并行(Parallerism)
    • 并发
      并发和并行都代表两个或者多个任务同时执行,并发表示任务的交替执行
    • 并行
      表示真正意义上的“同时执行”,需要多核cpu的支持
  • 临界区
    临界区是一种公共资源/共享资源,可以被多个线程同时使用,但如果一个线程正在使用临界区资源,那么其他线程必须等待。
  • 阻塞(Blocking),非阻塞(Non-Blocking)
    • 阻塞
      用来形容多线程之间的相互影响,当一个线程正在使用临界区资源,那么其他线程必须等待,等待就会导致线程挂起,这种情况就是阻塞,如果占用资源的线程一致不释放资源,那么其他线程就会阻塞在临界区上不能工作
    • 非阻塞
      与阻塞相反,非阻塞代表,没有任何一个线程可以防癌其他线程的执行,所有线程都会尝试不断向前执行
  • 死锁(Deadlock),饥饿(Starvation),活锁(Livelock)
    这些都是多线程的活跃性问题,发生其中任意一种情况,相关线程可能就无法继续执行
    • 死锁
      在多线程任务中,每个线程都占用对方资源,导致任务无法继续执行的情况
    • 饥饿
      在一个或者多个线程中,由于各种原因导致无法获取所需资源,无法继续执行的情况,如优先级低,或者线程被阻塞了
    • 活锁
      以生活中的例子来比喻,比如你刚准备进入电梯,电梯里的某个人想要,出来不巧的是,你们刚好撞在一起,你向左避让对方,对方刚好向右避让,这种来回的避让导致你们两都没法进入或走出电梯,这就是活锁的场景
并发级别 由于临界区的存在,多线程的并发必须受到控制,根据并发的策略大致有一下几种
  • 阻塞(Blocking)
    一个线程是阻塞的那么,在其他线程没有释放资源前,当前线程无法继续执行,我们可以用synchronized关键字或者重入锁得到一个阻塞的线程
  • 无饥饿(Starvation-Free)
    如果存在优先级的多个线程,高优先级的线程会优先于低优先级的线程,这样就会导致低优先级的线程无法继续执行,进入饥饿状态,这样是不公平的,可以通过公平锁的方式来依照先来后到的原则让每个线程都能都执行
  • 无障碍(Obstruction-Free)
    无障碍是最弱的一种非阻塞调度,多线程任务中,多个线程同时无障碍的执行,他们不会因为临界区的问题导致,线程挂起的现象,但是如果多个线程同时操作临界区资源,那么就要对自己所做的修改进行回滚,确保数据安全,如果没有数据竞争发生,那么线程就会顺利完成工作走出临界区
  • 无锁(Lock-Free)
    无锁的并行都是无障碍的。在无锁中所有线程尝试对临界区进行访问,但不同的是无锁的并发保证,必然有一个线程在有限步骤内完成操作离开临界区,但是有可能会出现某些线程在争夺临界区资源时一直失败,出现饥饿现象
  • 无等待(Wait-Free)
    为了解决无锁中可能会有线程出现饥饿现象的问题,无等待要求所有线程必须在有限步骤之内完成
  • 无等待(Wait-Free)
    为了解决无锁中可能会有线程出现饥饿现象的问题,无等待要求所有线程必须在有限步骤之内完成
JMM 并行程序要比串行程序复杂,最重要的是保证数据的一致性和安全性
  • 原子性(Atomicity)
    原子性是指一个操作的不可中断,在多线程一起执行时,一个操作一旦开始,就不会受其他线程的干扰
  • 可见性(visibility)
    当一个线程修改了某一共享变量的值,其他变量能否立即获取这个修改,会导致可见性原因,如缓存优化,指令重排
  • 有序性(ordering)
    由于指令重排这种机制的存在,导致程序的顺序和真正的执行顺序可能不一致,在串行程序中有序性问题是不存在的,在并行程序中,指令重排后无法保证并行程序中的语义一致。这就是在多线程中有序性问题的根本所在
以上大概就是学习java多线程前,必须要了解的一些知识,这些内容有助于java多线程的学习,避免一开始由于缺少基础知识,带来学习上的障碍。

    推荐阅读