并发编程简介 将串行执行部分编程并发执行,但要考虑上下文切换和资源调度的时间 并发编程的意义及影响多线程的因素 并发编程的目的是为了让程序运行得更快,但是,并不是启动更多的线程就能让程序最 大限度地并发执行。 影响多线程运行速度的原因有上下文切换、死锁,以及硬件和软件的资源限制等 资源限制:硬件资源和软件资源 硬件资源:如宽带 硬盘读写 内存 cpu处理速度 软件资源:如数据库连接数、socket连接数等 上下文切换 即使是单核处理器也支持多线程执行代码,CPU通过给每个线程分配CPU时间片来实现这个机制。时间片是CPU分配给各个线程的时间,因为时间片非常短,所以CPU通过不停地切 换线程执行,让我们感觉多个线程是同时执行的,时间片一般是几十毫秒(ms)。 CPU通过时间片分配算法来循环执行任务,当前任务执行一个时间片后会切换到下一个任务。但是,在切换前会保存上一个任务的状态,以便下次切换回这个任务时,可以再加载这个任务的状态。所以任务从保存到再加载的过程就是一次上下文切换。 上下文切换也会影响多线程的执行速度 多线程程序的评量标准 安全性——不损坏对象 暗指对象的字段所取得的值并非预期值 生存性——进行必要的处理 复用性——可再利用类 性能——能快速、大量进行处理
多线程执行不一定比串行执行快 除了上面提到的影响多线程的原因,还有线程有创建和上下文切换的开销 但可以通过调优减少上下文切换的方法有无锁并发编程、CAS算法、使用最少线程和使用协程。因为多线程竞争锁时,会引起上下文切换。
协程:在单线程里实现多任务的调度,并在单线程里维持多个任务间的切换。 并发工具分析 vmstat可以测量上下文切换的次数 用jstack命令dump线程信息,可以查看指定pid的进程里的线程都在做什么,例如:jstack pid,可以使用jstack pid > dump,然后使用: grep java.lang.Thread.State dump17|awk '{print $2$3$4$5}'|sort|uniq -c做统计,可以查看当前运行RUNNABLE、WAITING等状态的数量 死锁 两个线程分别获取了锁定,互相等待另一线程解除锁定的现象。发生死锁时,哪个线程都不能执行下去,所以程序就失去了生命性。 避免一个线程同时获取多个锁,避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源。尝试使用定时锁,使用lock.tryLock(timeout)来替代使用内部锁机制。对于数据库锁,加锁和解锁必须在一个数据库连接里,否则会出现解锁失败的情况。
引用书籍:《Java并发编程艺术》《Java多线程设计模式》