
并发编程
文章平均质量分 74
リュウセイリョウ
这个作者很懒,什么都没留下…
展开
-
IO多路复用的三种机制Select、Poll、Epoll
select、poll和epoll都是IO多路复用机制,可以监视多个文件描述符fd(每个fd关联了对应的socket),一旦某个fd有事件发生,就能够通知程序进行相应的IO操作。(select,poll,epoll本质上都是同步I/O,因为他们都需要在读写事件就绪后自己负责进行读写,也就是说读写过程是阻塞的,而异步I/O则无需自己负责进行读写,异步I/O的实现会负责把数据从内核拷贝到用户空间。)epoll是linux2.6以后Linux特有的实现机制,select则是一般OS都有的实现机制。1、sele原创 2021-05-08 18:00:48 · 292 阅读 · 0 评论 -
并发:读写锁ReentrantReadWriteLock和StampedLock
1. 读写锁读写锁通常遵守以下三条规则:多个线程可以同时读共享变量;只允许一个线程写共享变量;对共享变量写的时候,不允许对该变量读。简单来说,读写锁允许同时读,读和写互斥,写和写互斥。因此,在读多写少的场景下,读写锁比普通的互斥锁更具优势。2. 读写锁ReentrantReadWriteLockReentrantReadWriteLock从字面上来看,可以知道它是一个可重入的读写锁。在使用容器时,使用ReentrantReadWriteLock,可以实现较好的并发性能,尤其是在读多写少原创 2021-01-05 16:18:01 · 407 阅读 · 0 评论 -
并发:java内存模型
1. 前言可见性、有序性和原子性导致了并发编程的各种问题。导致可见性的原因是缓存,导致有序性的原因是编译优化。解决这两个问题的直接方法就是按需禁用缓存和编译优化。java内存模型规范了JVM如何提供按需禁用内存和编译优化的方法。这些技术主要包含volatile关键字、Happens-Before规则和final关键字。2. volatilevolatile关键字用于修饰一个变量,作用就是禁用缓存。当一个变量被volatile修饰,就是要告诉编译器,只能从内存中读取该变量,也只能写入到内存中。3原创 2021-01-04 21:06:09 · 147 阅读 · 0 评论 -
JDK源码阅读(十三) : 单端阻塞队列——ArrayBlockingQueue
1. 队列队列是一种先进先出(First In First Out)的数据结构。可以分成阻塞和非阻塞两类:阻塞队列,即如果队列已满,入队操作会阻塞;如果队列为空,出队操作也会阻塞。(Blocking标识)非阻塞队列,即如果队列已满,执行入队操作会直接返回;如果队列为空,执行出队操作也是直接返回。也可以分成单端和双端两类:单端队列,即只能在队尾入队,队首出队;(Queue标识)双端队列,队首队尾都可以出队。(Deque标识)单端阻塞队列:主要有ArrayBlockingQueue(内原创 2020-12-29 21:28:19 · 246 阅读 · 0 评论 -
JDK源码阅读(十二) : 基于跳表的并发容器——ConcurrentSkipListMap
1. 简介ConcurrentSkipListMap是有序的hash表,是线程安全的。与之对比的另外两种hash容器,ConcurrentHashMap虽然是线程安全的,但是key并不是有序的;而TreeMap虽然key是有序的,但是不是线程安全的。ConcurrentSkipListMap采用无锁方案,支持更高的并发,存取时间是O(logN),与线程数无关。也就是说,当数据量一定的情况下,并发线程数越多,ConcurrentSkipListMap优势越大。2. 数据结构ConcurrentSki原创 2020-12-29 16:38:25 · 383 阅读 · 1 评论 -
JDK源码阅读(十一) : 并发容器——ConcurrentHashMap
1. Why ConcurrentHashMap?在java1.7版本,数组中发生冲突的节点以链表形式相连,在进行HashMap在执行put方法时,通过头插法插入到单链表中。然而put过程中可能会触发扩容操作,此时会将原数组的内容重新散列(rehash)到新的数组中。在多线程环境下,如果多个线程同时执行put方法,可能会使数组某一位置上的链表形成闭环,继而出现死循环,cpu飙升到100%。所以java1.7中的hashmap不是线程安全的。而同步容器HashTable虽然是线程安全的,但是锁的粒度太大,原创 2020-12-28 17:02:46 · 222 阅读 · 0 评论 -
JDK源码阅读(十) : 并发容器——CopyOnWriteArrayList
1. 同步容器和并发容器Java1.5以前,提供线程安全的容器是同步容器,比如Vector、Stack 和 Hashtable,这些容器使用synchronized关键字修饰方法,以保证互斥。这种方式的串行度太高,所以效率很低。Java1.5开始,提供了性能更好的并发容器。并发容器也可分成四大类:List、Map、Set和Queue。2. CopyOnWriteArrayListCopyOnWriteArrayList是ArrayList的线程安全版本,从名称上来看,它是写时复制的ArrayList原创 2020-12-23 17:21:33 · 202 阅读 · 0 评论 -
并发:发生死锁和处理死锁
1、什么是死锁?死锁指一组互相竞争系统资源的进程/线程永久性地阻塞 (以下线程同进程)。当一组线程中的每个线程都在请求某些资源,而这组线程中被阻塞的其他线程已经占用了这些资源,没有其他任何线程会再释放出这些资源,于是就发生了死锁,死锁是永久的。2、发生死锁的条件死锁有三个必要条件:①互斥。一次只有一个线程可以使用一个资源。②占有且等待。当一个线程已占用了某些资源,在请求等待其他资源的时候,不释放已占用的资源。③不可抢占。其他线程不能强行抢占线程已经占用的资源。这三个条件是发生死锁的必要条件,而原创 2020-11-05 16:03:12 · 558 阅读 · 0 评论 -
并发:管程
1、为什么使用管程?信号量可以提供线程间的互斥和合作,但是使用信号量来设计一个正确的程序时很困难的,semWait和semSignal可能会分布在整个程序中,很难看出信号量上的这些操作所产生的整体效果。管程(monitor)是一种程序设计语言结构,它提供与信号量相同的功能,但更容易控制。2、什么是管程?管程是包含共享变量以及对共享变量的操作方法的过程,让它们支持并发。管程的特点:①共享变量只能被管程中的方法访问,外部过程不能访问;②一个线程只能通过调用管程的一个方法进行管程;③任何时候,只能原创 2020-11-04 14:10:20 · 453 阅读 · 0 评论 -
并发:信号量
信号量(Semaphore)是用于进程/线程间传递信号的一个整数值。在信号量上只可以进行三种操作,即初始化、递减和递增,这三种操作都是原子操作。递减semWait():信号量的值减1,如果小于0,则当前线程被阻塞,否则可以继续执行,递减操作也称为P操作;递增semSignal():信号量的值加1,如果小于等于0,则从等待队列中唤醒一个线程,使其就绪,递增操作也称为V操作。信号量模型也被称为PV原语。java语言中,信号量模型由java.util.concurrent.Semaphore实现。semWa原创 2020-11-04 14:05:33 · 491 阅读 · 0 评论 -
并发:互斥锁
为了保证某段程序的原子性,需要使得同一时刻只有一个线程执行,这就是互斥。一段需要互斥执行的代码称之为临界区。线程进入临界区之前,首先试图执行加锁操作lock(),如果成功加锁,则进行临界区执行,此时该线程持有锁;否则就等待其他进程释放锁;持有锁的线程离开临界区后需要释放锁unlock()。我们都知道锁是用来保护临界资源的,也就是共享变量、共享文件等资源,那么锁的是什么呢?1、synchronized关键字Java中的synchronized关键字是java在语言层面提供的互斥原语,是锁的一种实现。原创 2020-11-04 14:03:51 · 393 阅读 · 0 评论 -
并发问题的源头
1、并发程序的问题并发是很多问题的基础,也就是操作系统设计的基础。并发包括很多设计问题,其中有进程/线程通信、资源共享与竞争(如内存、IO设备)、进程/线程同步等。由于进程/线程的相对执行速度不可预测,它取决于其他进程/线程的活动、操作系统处理中断的方式以及操作系统的调度策略,于是就产生了以下困难:全局资源的共享存在危险。如果两个进程/线程对同一个全局变量进行读写操作,那么读写的执行顺序非常重要。操作系统的资源分配问题。两个进程互相占用了对方进程所请求的资源,那么就会产生永久地等待,即死锁。定位程原创 2020-11-03 11:33:35 · 293 阅读 · 0 评论