并发编程三要素

  • 原子性
    • 一个不可再被分割的颗粒,原子性指的是一个操作要么全部执行成功要么全部执行失败。
    • 期间不能被中断,也不存在上下文切换,线程切换会带来原子性问题。
  • 有序性
    • 程序执行的顺序按照代码的先后顺序执行,因为处理器可能会对指令进行重排序。
  • 可见性
    • 一个线程A对共享变量的修改,另一个线程B能够立刻看到

常见的锁种类

  • 悲观锁
    • 当线程去操作数据的时候,总认为别的线程回去修改数据,所以每次它拿数据的时候都会上锁,别的线程去拿数据的时候就会阻塞,比如synchronized、ReentrantLock
  • 乐观锁
    • 每次去拿数据的时候都认为别人不会修改,更新的时候会判断是别人是否回去更新数据,通过版本来判断。
    • 如果数据被修改了就拒绝更新,比如CAS就是乐观锁,但严格来说并不是锁,通过原子性来保证数据的同步
    • 比如数据库的乐观锁,通过版本控制来实现,乐观的认为在数据更新期间没有其他线程影响。
  • 公平锁

    • 指多个线程按照申请的顺序来获取锁,简单来说,如果一个线程组里,能保证每个线程都能拿到锁。
    • 比如ReentrantLock(底层是同步队列FIFO:First Input First Output来实现)
  • 非公平锁

    • 获取锁的方式是锁机获取的,保证不了没哥线程都能拿到锁,也就是存在有线程饿死,一直拿不到锁。
    • 比如synchronized、ReentrantLock
  • 独享锁(互斥锁)

    • 也叫他排它锁/写锁/独占锁/独享锁/该锁每一次只能被一个线程所持有,枷锁后任何线程试图再加锁的线程会被阻塞直到当前线程解锁。例如:线程A对data1加上排他锁,则其他线程不能再对data1加任何类型的锁。
    • 获得互斥锁的线程即能读数据又能修改数据
  • 共享锁

    • 也叫S锁/读锁,你那个查看但无法修改和删除的一种数据锁,加锁后其他用户可以并发读取,查询数据但不能修改、增加、删除数据,该锁可被多个线程所持有,用于资源数据共享。
  • 可重入锁

    • 也叫递归锁,在外层使用锁之后,在内存仍然可以使用,并且不发生死锁
  • 不可重入锁

    • 若当前线程执行某个方法已经获取了该锁,那么在方法中尝试再次获取锁时,就会获取不到被阻塞。
  • 自旋锁
    • 一个线程在获取锁的时候,如果锁已经被其他线程获取,那么该线程将循环等待,然后不断的判断锁匙放能够被成功获取,知道获取到锁才会退出循环,任何时候最多只能又一个执行单元获取该锁。
    • 不回发生线程状态切换,一直处于用户态,减少了线程上下文切换的消耗,缺点是循环会消耗CPU。
  • 分段锁
    • 并不是具体的一种锁,只是一种锁的设计,将数据分段上锁,把锁进一步细化粒度,可以提升并发量,当操作不需要更新整个数组的时候,就仅针对数组中的一项进行加锁操作,比如CurrentHashMap底层就用了分段锁。
  • 死锁
    • 两个或两个以上的线程在执行过程中,由于竞争资源或由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法让程序进行下去
07-06 22:43