并发实战——并发相关知识点overview

本章内容:

  • 总结下并发有关问题(以某公司并发编程讲座为参考资料)

1、java的并发模型和操作系统有关么?

操作系统的不同会影响java中并发模型的实现方式。
Java在JVM层面抽象了一套自己的线程机制(里面的规则和操作系统层面的有一定相似性),用以映射不同的操作系统的任务调度。

譬如早期不支持线程的操作系统,jvm在操作系统上面是一个进程,当这个进程被操作系统调度到后,jvm内部实现的线程库再调度java线程。

之后,当操作系统开始支持多线程(如windows从一开始就支持线程),这样java线程就和操作系统线程一一对应或多多对应了,这个时候,如果是一一对应,那么线程的调度完全交给了操作系统内核,当然jvm还保留一些策略足以影响到其内部的线程调度。

比如线程模型中很多的实现都是native方法,native关键字的函数都是操作系统实现的, java只能调用。

如果一个机器上只有一个逻辑CPU,此时系统调度器通过轮换时间片的方式来调度任务,所以不存在真正的并行,只是并发;只有多个逻辑CPU的情形下,才会出现并行。

http://blog.csdn.net/gatieme/article/details/51481863


2、并发相关特性和解决办法
Visibility:通过并发线程修改变量值, 必须将线程变量同步回主存后, 其他线程才能访问到。volatile
Ordering:通过java提供的同步机制或volatile关键字(也可以是实现Visibility), 来保证内存的访问顺序。
Cache coherency :它是一种管理多处理器系统的高速缓存区结构,其可以保证数据在高速缓存区到内存的传输中不会丢失或重复。
Happens-before :synchronized,volatile,final,java.util.concurrent.lock,atomic

Java存储模型有一个happens-before原则,就是如果动作B要看到动作A的执行结果(无论A/B是否在同一个线程里面执行),那么A/B就需要满足happens-before关系

  • 程序次序规则:一个线程内,按照代码顺序,书写在前面的操作先行发生于书写在后面的操作;
  • 锁定规则:一个unLock操作先行发生于后面对同一个锁的lock操作;
  • volatile变量规则:对一个volatile变量的写操作先行发生于后面对这个变量的读操作;
  • 传递规则:如果操作A先行发生于操作B,而操作B又先行发生于操作C,则可以得出操作A先行发生于操作C;
  • 线程启动规则:Thread对象的start()方法先行发生于此线程的每个一个动作;
  • 线程中断规则:对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生;
  • 线程终结规则:线程中所有的操作都先行发生于线程的终止检测,我们可以通过Thread.join()方法结束、Thread.isAlive()的返回值手段检测到线程已经终止执行;
  • 对象终结规则:一个对象的初始化完成先行发生于他的finalize()方法的开始;

开始接触happens-before规则和指令重排序的时候,着实乱了以阵子,尤其是happens-before规则的第一条,明明说了同一个线程中每个动作都happens-before其后一个动作,而指令重排序又会对没有依赖的两个操作进行重排序,这不是相互矛盾的么?

经过网上翻阅了一些资料以后,我的理解是,happens-before规则是用来判断一个动作对另一个动作是否可见的法则,他只是用来判断可见性的,而不是决定执行顺序的,就是说动作A和动作B 的执行顺序是可以通过指令重排发生变化的,而如果你要保证A和B的可见性关系,就必须采用其他控制手段来保证AB的执行顺序不被打乱,这样就能用happens-before规则来判断AB两个动作的可见性。


3、分离锁
这里写图片描述

分离锁负面作用:对容器加锁,进行独占访问更加困难,并且更加昂贵了。

内存使用的问题:sina就曾经因为在Action层使用ConcurrentHashMap而导致内存使用过大,修改array后竟然单台服务器节省2G。

https://www.ibm.com/developerworks/cn/java/j-lo-lock/(如何更聪明地使用锁)


4、volatile关键字:

volatile关键字:
1:简化实现或者同步策略验证的时候来使用它;
2:确保引用对象的可见性;
3:标示重要的生命周期的事件,例如:开始或者关闭。

脆弱的volatile的使用条件:
1:写入变量不依赖变量的当前值,或者能够保证只有单一的线程修改变量的值;
2:变量不需要和其他变量共同参与不变约束;
3:访问变量时不需要其他原因需要加锁。

Volatile 变量是一种非常简单但同时又非常脆弱的同步机制,它在某些情况下将提供优于锁的性能和伸缩性。如果严格遵循 volatile 的使用条件即变量真正独立于其他变量和自己以前的值 ,在某些情况下可以使用 volatile 代替 synchronized 来简化代码。

http://blog.csdn.net/lazyer_dog/article/details/52345914


5、几个建议

对共享可变数据同步访问;
避免过多的同步;
永远不要在循环外面调用wait;
不要依赖于线程调度器;
线程安全的文档化;
避免使用线程组。


6、JUC包
这里写图片描述

Executors

Executor
ExecutorService
ScheduledExecutorService
Callable
Future
ScheduledFuture
Delayed
CompletionService
ThreadPoolExecutor
ScheduledThreadPoolExecutor
AbstractExecutorService
Executors
FutureTask
ExecutorCompletionService

Queues

BlockingQueue
ConcurrentLinkedQueue
LinkedBlockingQueue
ArrayBlockingQueue
SynchronousQueue
PriorityBlockingQueue
DelayQueue

Concurrent Collections

ConcurrentMap
ConcurrentHashMap
CopyOnWriteArray{List,Set}

Synchronizers

CountDownLatch
Semaphore
Exchanger
CyclicBarrier

Timing

TimeUnit

Locks

Lock
Condition
ReadWriteLock
AbstractQueuedSynchronizer
LockSupport
ReentrantLock
ReentrantReadWriteLock

Atomics

Atomic[Type], Atomic[Type]Array
Atomic[Type]FieldUpdater
Atomic{Markable,Stampable}Reference


7、线程池

1:线程池的大小最好是设定好,因为JDK的管理内存毕竟是有限的;
2:使用结束,需要关闭线程池;
3: Runtime.getRuntime().addShutdownHook(hook); 对不能正常关闭的
线程做好相关的记录。


8、任务池

任务池: ScheduledExecutorService


9、阻塞队列:BlockingQueue

生产者消费者模型中,会用到阻塞队列。

各种阻塞队列:
ArrayBlockingQueue:一个由数组支持的有界阻塞队列。此队列按 FIFO(先进先出)原则对元素进行排序。
Delayed 元素的一个无界阻塞队列,只有在延迟期满时才能从中提取元素.
LinkedBlockingDeque一个基于已链接节点的、任选范围的阻塞双端队列。
LinkedBlockingQueue一个基于已链接节点的、范围任意的 blocking queue。此队列按 FIFO(先进先出)排序元素
PriorityBlockingQueue一个无界阻塞队列,它使用与类 PriorityQueue 相同的顺序规则,并且提供了阻塞获取操作。
SynchronousQueue一种阻塞队列,其中每个插入操作必须等待另一个线程的对应移除操作 ,反之亦然。


10、ConcurrentHashMap
这里写图片描述

ConcurrentHashMap主要的知识点:锁分离,hash算法


11、CopyOnWriteArray{List,Set}

当读操作远远大于写操作的时候,考虑用这个并发集合。例如:维护监听器的集合。注意:其频繁写的效率可能低的惊人。


12、四大同步器
同步器是一些使线程能够等待另一个线程的对象,允许它们协调动作。最常用的同步器是CountDownLatch和Semaphore,不常用的是Barrier 和Exchanger

这里写图片描述

这里写图片描述

这里写图片描述


13、互斥锁: ReentrantLock

Lock 更加灵活,性能更好

interface Lock {
        void lock();
        void lockInterruptibly() throws InterruptedException;
        boolean tryLock();
        boolean tryLock(long timeout, TimeUnit unit)
                    throws InterruptedException;
        void unlock();
        Condition newCondition();
    }

支持多个Condition
可以不以代码块的方式上锁
可以使用tryLock,并指定等待上锁的超时时间
调试时可以看到内部的owner thread,方便排除死锁
RenntrantLock支持fair和unfair两种模式


14、读写锁: ReadWriteLock

ReadWriteLock 维护了一对相关的锁,一个用于只读操作,另一个用于写入操作。只要没有 writer,读取锁可以由多个 reader 线程同时保持。写入锁是独占的。


15、AbstractQueuedSynchronizer

  • 为实现依赖于先进先出 (FIFO) 等待队列的阻塞锁和相关同步器(信号量、事件,等等)提供一个框架;
  • 基于JDK底层来操控线程调度,LockSupport.park和LockSupport.unpark;
  • 此类支持默认的独占 模式和共享 模式之一,或者二者都支持;
  • 如果想玩玩它,请看CountDownLatch的源码。
  • 当然,也可以去FutureTask这个类看看。
  • -

16、CAS

乐观锁
处理器指令,全称Compare and swap,原子化的读-改-写指令
处理竞争策略:单个线程胜出,其他线程失败,但不会挂起

目前的多处理器系统基本都支持原子指令,典型模式:首先从V中读取值B,由A生成新值B,然后使用CAS原子化地把V的值由A修改成B,并且期间不能有其他线程修改V的值,CAS能够发现来自其他线程的干扰,所以即使不使用锁,也能解决原子化地读-写-改的问题


非阻塞算法

  • 一个线程的失败或挂起不影响其他线程
  • J.U.C的非阻塞算法依赖Atomic
  • 算法里一般采用回退机制处理Atomic的CAS竞争
  • 对死锁免疫的同步机制
  • 目标:相对阻塞算法,减少线程切换开销、减少锁的竞争等。
  • 也是Lock-free,即无锁编程

编程实践

使用更优的锁
缩小锁的范围

  • 减少线程把持锁的时间
  • 避免在临界区进行耗时计算
  • 常见做法1:缩小同步快
  • 常见做法2:把一个同步块分拆成多个
  • 需要保证业务逻辑正确为前提

避免热点域

  • 热点域:每次操作,都需要访问修改的fields
  • eg. ConcurrentHashMap的size计算问题

使用不变和Thread Local 的数据

  • 不变数据,即Immutable类型数据、在其生命周期中始终保持不变,可以安全地在每个线程中复制一份以便快速读取。
  • ThreadLocal数据,只被线程本身使用,因此不存在不同线程之间的共享数据的问题。

使用高并发容器

高速缓存计算结果

安全发布

利用成熟的框架


ThreadLocal
http://blog.csdn.net/youyou1543724847/article/details/52460852

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
信息数据从传统到当代,是一直在变革当中,突如其来的互联网让传统的信息管理看到了革命性的曙光,因为传统信息管理从时效性,还是安全性,还是可操作性等各个方面来讲,遇到了互联网时代才发现能补上自古以来的短板,有效的提升管理的效率和业务水平。传统的管理模式,时间越久管理的内容越多,也需要更多的人来对数据进行整理,并且数据的汇总查询方面效率也是极其的低下,并且数据安全方面永远不会保证安全性能。结合数据内容管理的种种缺点,在互联网时代都可以得到有效的补充。结合先进的互联网技术,开发符合需求的软件,让数据内容管理不管是从录入的及时性,查看的及时性还是汇总分析的及时性,都能让正确率达到最高,管理更加的科学和便捷。本次开发的医院后台管理系统实现了病房管理、病例管理、处方管理、字典管理、公告信息管理、患者管理、药品管理、医生管理、预约医生管理、住院管理、管理员管理等功能。系统用到了关系型数据库中王者MySql作为系统的数据库,有效的对数据进行安全的存储,有效的备份,对数据可靠性方面得到了保证。并且程序也具备程序需求的所有功能,使得操作性还是安全性都大大提高,让医院后台管理系统更能从理念走到现实,确确实实的让人们提升信息处理效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值