java-多线程与锁

多线程与锁

多线程并发执行任务的过程中,通过锁将并行的任务转为串行任务执行。

synchronized 对象锁

  • 自动加锁和解锁
  • 锁升级过程(了解jmm java内存布局)
    • 无锁 只有一个线程时,标志位0,记录threadId
    • 偏向锁 两个线程竞争,标志位1,记录threadId
    • 自旋锁 多个线程但竞争不大时,都会先尝试获取锁(默认10次)
    • 重量级锁 多个线程竞争锁而且尝试多次获取不到时,进入阻塞队列,依次执行

lock 显式锁

  • lock/tryLock 获取锁

  • unlock 释放锁

  • java.util.concurrent.locks.ReentrantLock 可重入锁

  • java.util.concurrent.locks.ReentrantReadWriteLock 读写锁
    写加锁,读不加锁

  • java.util.concurrent.ConcurrentHashMap

cas (compareAndSwap)

  • 自旋锁、乐观锁、无锁

  • 原子操作(cpu级别保证操作不会发生指令重排)

    • java.util.concurrent.atomic.AtomicInteger
  • sun.misc.Unsafe jdk提供的原子操作方法的接口

    • unsafe.compareAndSwapInt(this, valueOffset, expect, update)
  • ABA问题

    • AtomicStampedReference 加时间戳解决ABA问题

      volatile 线程可见性

      多线程共享变量要加volatile,保证每个线程获取变量值时,都能从内存获取最新的,而不是获取自己线程栈内的变量值
  • ThreadLocal 是把一个变量在线程栈内复制多个副本,空间换时间

锁的类型

  • 乐观锁、悲观锁
    乐观锁:每个线程先尝试获取锁,获取不到后进入阻塞队列
    悲观锁:直接进入阻塞队列

  • 公平锁、非公平锁
    公平锁:每个线程都要进入阻塞队列排队后等待cpu调度
    非公平锁:抢占执行

  • 可重入锁、不可重入锁
    可重入锁:一个线程获取到外层锁后还可以获取内层锁
    不可重入锁:一个线程获取外层锁后,只有释放后才能获取内层锁

  • 偏向锁

  • 行锁、表锁

  • 读写锁

多线程

线程与进程

  • cmd java命令,即可启动一个jvm就是一个进程(包含一个main线程)
  • main线程可以创建一或多个子线程
  • deamon线程下的普通线程执行完后,会自动结束(如gc-deamon线程,会自动结束)

如何创建线程

  • 继承Thread类
  • 实现Runnable接口
  • Callable/Future/CompletableFuture 有返回值

线程的状态与变化

graph LR;

New --start--> Runnable --获得cpu时间片--> Running --运行完成--> Dead 

Running --执行完cpu时间片--> Runnable

Running --sleep/锁等待--> Blocked --sleep结束/获得锁--> Runnable

线程的方法

  • join 主线程在此处会等待子线程执行完
  • sleep 当前线程进入阻塞态,会释放cpu,但不会释放锁
  • wait 释放cpu,不释放锁
  • yield 释放cpu
  • notifyAll 唤醒cpu与持有锁的线程

线程池是什么?线程池的创建?

  • java.util.concurrent.Executors

    • newCachedThreadPool 无限的新线程
    • newFixedThreadPool 核心线程数固定,无限排队线程
    • newSingleThreadExecutor 只有一个线程运行,其他线程排队
    • newScheduledThreadPool 定时执行线程
    • newWorkStealingPool 抢占式运行线程
  • java.util.concurrent.ThreadPoolExecutor
    可根据需要定制线程池

    1
    2
    3
    4
    5
    6
    7
    public ThreadPoolExecutor(int corePoolSize,  核心(初始化)线程数
    int maximumPoolSize, 最大线程数
    long keepAliveTime, 存活时间
    TimeUnit unit,
    BlockingQueue<Runnable> workQueue, 任务队列
    ThreadFactory threadFactory, 线程工厂
    RejectedExecutionHandler handler) 拒绝策略
  • BlockingQueue 阻塞队列

    • ArrayBlockingQueue
    • LinkedBlockingQueue
    • DelagedWorkQueue
  • ThreadFactory 线程工厂

  • RejectedExecutionHandler 拒绝策略

    • ThreadPoolExecutor.AbortPolicy
    • ThreadPoolExecutor.DiscardPolicy

线程安全

多线程下编程时,导致结果不唯一的处理方式都是不安全的,

多线程时会遇到哪些问题?

  • 指令重排 (加锁,原子操作)
  • 伪共享 (volatile、ThreadLocal)
  • 线程安全

如何停止正在运行的线程?

使用标志位,在线程运行时,定期去检查标志

  • jvm stop-the-world
  • tomcat stop

线程同步类

通过这些类,可以给多个异步执行的线程设置集合点,在此以后可以同步执行

  • java.util.concurrent.CountDownLatch 计数器

  • java.util.concurrent.CyclicBarrier 循环栅栏

  • java.util.concurrent.Semaphore 信号量