并发编程

并发、并行与串行

  1. 并发:单核多任务,按时间片轮流交替执行
  2. 并行:多核多任务,同时进行
  3. 串行:多个任务按顺序进行

线程与进程

进程是资源分配的基本单位,线程任务调度与执行的基本单位
线程又被称为轻量级进程,同一进程中的线程共享进程的资源,线程之间切换的开销要远小于进程之间的切换

什么是上下文切换

cpu采用的是为每个线程分配时间片并轮转的形式,当千任务在执行完cpu时间片会切换到另一任务前会保存自己的状态,以便下次切换回这个任务可以加载这个任务状态。任务从保存到再加载的过程就是一次上下文切换,计算密集型,可能是
操作系统中消耗最大的操作。

多线程的问题

  • 线程多,占用内存高
  • 线程管理需要CPU时间跟踪
  • 线程之间对共享资源的访问会相互影响,因此要解决竞争共享资源的问题

查找cpu利用率高的线程

  1. top: 找到利用率最高的进程的pid
  2. top -H -p pid:找出进程中利用率最高的线程、
  3. 转16进制
  4. jstack pid > /tem t.dat:打印进程信息
  5. 查看该日志文件
线程死锁的条件
互斥
请求保持
不可剥夺
循环等待
创建线程的方法
  1. 继承Thread类,重写run方法
  2. 实现runnable接口,重写run,作为参数传递给Thread类
  3. 实现callable方法,重写call,作为参数传给FutureTask,再传给Thread,可以获得返回值
  4. 线程池:全部实现ExectuorService接口
    并发编程
    其中Executors工具类提供了一系列方法用于创建线程池
    newFixedThreadPool,newSingleThreadExecutor-------容易任务堆积出现溢出
    newCachedThreadPool,newScheduledThreadPool-------线程过多出现溢出

FutureTask
并发编程
运算没结束get方法会一直阻塞

线程生命周期

并发编程

wait/notify/notifyAll

必须在同步块中调用,wait会释放锁notify要获取锁,他们是object的方法,因为任何一个对象都可以获取多个锁

线程池流程
  1. *队列:一直添加
  2. 有界队列:
    并发编程
    1. Abort:抛出异常
    2. Discard:直接丢弃
    3. DiscardOldest:丢弃最老的
    4. callerrun:由调用线程去处理

Happends-before

  1. volatile的写操作发生在读操作前
  2. 线程启动先于该线程的其他操作
  3. 线程内按顺序
  4. unlock发生在lock前
  5. interrupt一定发生在线程的中断前
  6. 线程内任何操作都先于检测到该线程结束
  7. 构造先于finalizer前
  8. 传递性

AQS

一个用来构建锁和同步器的框架
核心思想:
请求的资源空闲,则将请求该资源的线程置为有效线程并将资源锁定,若是被占用,则将其加入等待队列,AQS使用CLH(虚拟双向队列,将线程封装成一个节点并维持节点之间的关系)来实现锁分配
并发编程
AQS使用一个volatile修饰的共享变量表示同步状态
资源的共享方式:

  1. 独占:只允许一个线程执行
    1. 公平锁:按顺序
    2. 非公平锁:抢占式
  2. 共享:countdownLatch、cyclicBarrier…

线程池
建议ThreadPoolExecutor来自己手动编写
1. core
2. max
3. queue
4. keepAlive
5. 单位
6. ThreadFactory
7. 拒绝策略