多线并发实战

                                          多线程并发实战

                  线程安全

                    Java 提供了内置锁, 来解决线程安全,  内部是一个监视器,  通过一些进入, 退出命令, 对对象实现原子性操作。 jvm  级别锁。

                  关于内置锁的重入的问题 实现Java 监视器模式

                  当一个锁锁住对象的时候  其他线程进入阻塞状态。这个线程再次发出请求的时候会重入。

                   共享对象

                   可见性:Java内存模型 主内存和工作内存

                    每次读取工作内存都从主内存加载最新的数据

                    每次修改工作内存的数据加载到主内存中。

                    可见性保证修改数据被其他线程可见。Vloatile 通过store load 等指令保证可见性 内置锁和Vloatile 都能保证可见性。

                    线程封闭

                     不共享数据 threadlocal  线程变量

                     不变对象线程安全

 

                     同步容器

                      早期的vector 和hashtable 内部方法加了同步锁

                      Collection. Synchronized 可以相应的容器变成线程安全的

                      Concurrent 包下的ConcurrentHashMap  分段锁读取写入可以同时进行 减少了锁的粒度。基于分段锁

                      CopyAndWriteArrayList 等容器 每次写入时 重新复制一份写的容器 缺点数据量大 性能比较差

                      阻塞队列 实现了生产消费者模式。

                       同步工具

                       协调生产者消费者的控制流,信号量     闭锁(countdownlatch 可以等待一组线程事件 futureTask 也可以做为闭锁)    栅栏

                    Executeor 框架

                     基于生产消费者模式

                      线程池

                    

                    

public ThreadPoolExecutor(int corePoolSize,

                              int maximumPoolSize,

                              long keepAliveTime,

                              TimeUnit unit,

                              BlockingQueue<Runnable> workQueue,

                              ThreadFactory threadFactory,

                              RejectedExecutionHandler handler) {

  

    }

corePoolSize- 池中所保存的线程数,包括空闲线程。需要注意的是在初创建线程池时线程不会立即启动,直到有任务提交才开始启动线程并逐渐时线程数目达到corePoolSize。若想一开始就创建所有核心线程需调用prestartAllCoreThreads方法。

maximumPoolSize-池中允许的最大线程数。需要注意的是当核心线程满且阻塞队列也满时才会判断当前线程数是否小于最大线程数,并决定是否创建新线程。

keepAliveTime - 当线程数大于核心时,多于的空闲线程最多存活时间

unit - keepAliveTime 参数的时间单位。

workQueue - 当线程数目超过核心线程数时用于保存任务的队列。主要有3种类型的BlockingQueue可供选择:无界队列,有界队列和同步移交。中可以看到,此队列仅保存实现Runnable接口的任务。

threadFactory - 执行程序创建新线程时使用的工厂。

handler - 阻塞队列已满且线程数达到最大值时所采取的饱和策略。java默认提供了4种饱和策略的实现方式:中止、抛弃、抛弃最旧的、调用者运行

无界队列

队列大小无限制,常用的为无界的LinkedBlockingQueue,使用该队列做为阻塞队列时要尤其当心,当任务耗时较长时可能会导致大量新任务在队列中堆积最终导致OOM。最近工作中就遇到因为采用LinkedBlockingQueue作为阻塞队列,部分任务耗时80且不停有新任务进来,导致cpu和内存飙升服务器挂掉。

有界队列

常用的两类,一类是遵循FIFO原则的队列如ArrayBlockingQueue与有界的LinkedBlockingQueue,另一类是优先级队列如PriorityBlockingQueue。PriorityBlockingQueue中的优先级由任务的Comparator决定。

使用有界队列时队列大小需和线程池大小互相配合,线程池较小有界队列较大时可减少内存消耗,降低cpu使用率和上下文切换,但是可能会限制系统吞吐量。

同步移交

如果不希望任务在队列中等待而是希望将任务直接移交给工作线程,可使用SynchronousQueue作为等待队列。SynchronousQueue不是一个真正的队列,而是一种线程之间移交的机制。要将一个元素放入SynchronousQueue中,必须有另一个线程正在等待接收这个元素。只有在使用无界线程池或者有饱和策略时才建议使用该队列。

           

                      

                         

                    显示锁

reetrantLock 与lock  与内置锁不同的是   提供的无条件的 可轮询的 定时的可中断的 所以加锁和解锁都是显示的。

reetrantLock 公平和非公平两种机制

读写锁   读读不互斥 读写以及写写均互斥   使用于读多写少的程序

保证并发的实现

无锁的cas 机制 

会导致aba 问题  解决 时间戳  及版本号

ASQ 机制 锁的内部实现机制

分布式锁的实现  redis    以及zk 临时节点   或者放在mq 的队列里。

                  

 

 

 

                    

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值