互斥锁

读写锁之ReadWriteLock

江枫思渺然 提交于 2020-02-24 08:43:18
你可能有这样一个疑问,Java SDK 并发包里为什么还有很多其他的工具类呢?原因很简单: 分场景优化性能,提升易用性 。 接下来我们聊聊,针对读多写少这种并发场景,Java SDK 并发包提供了读写锁——ReadWriteLock 读写锁,并不是 Java 语言特有的,而是一个广为使用的通用技术,所有的读写锁都遵守以下三条,尤其注意第三条,之后我们讲跟其他锁的对比会用到。 基本原则: 1. 允许多个线程同时读共享变量; 2.只允许一个线程写共享变量; 3. 如果一个写线程正在执行写操作,此时禁止读线程读共享变量(读写锁不能同时存在) 互斥锁: 互斥锁 互斥锁 升降级 ReadWriteLock 读操作允许多个线程同时读共享变量 写操作是互斥的,当一个 线程在写共享变量的时候,是不允许其他线程执行写操作和读操作。 不允许升级,允许降级。 读锁不支持条件变量 newCondition() 读写锁在读多写少场景下性能优于互斥锁的关键 总结: 读写锁类似于 ReentrantLock,也支持公平模式和非公平模式。读锁和写锁都实现了 java.util.concurrent.locks.Lock 接口,所以除了支持 lock() 方法外,tryLock()、 lockInterruptibly() 等方法也都是支持的。但是有一点需要注意,那就是只有写锁支持条件变量, 读锁是不支持条件变量的

多线程编程总结

这一生的挚爱 提交于 2020-02-24 05:48:57
一、线程模型: 线程是程序中完成一个独立任务的完整执行序列,即一个可调度的实体。根据运行环境和调度者的身份,线程可分为 内核线程和 用户线程。 内核线程:运行在内核空间,由内核来调度; 用户线程:运行在用户空间,由线程库来调用。 当进程的一个内核线程获得CPU的使用权时,它就加载并运行一个用户线程。可见,内核程序相当于用户线程运行的容器。一个进程可以拥有M个内核线程和N个用户线程,其中M≤N。并且在一个系统的所有进程中,M和N的比值都是固定的。按照M:N的取值,线程的实现方式可分为三种模式: 完全在用户空间实现、 完全由内核调度和 双层调度。 1、完全在用户空间实现的线程无须内核的支持,内核甚至根本不知道这些现成的存在。线程库负责管理所有执行线程,比如线程的优先级、时间片等。线程库利用longjmp来切换线程的执行,使它们看起来像是“并发”执行的。但实际上内核仍然是把整个进程作为最小单位来调度的。换句话说,一个进程的所有执行线程共享该进程的时间片,它们对外表现出相同的优先级。因此,对于这种实现方式而言,M=1,即N个用户空间线程对应1个内核线程,而该内核线程实际上就是进程本身。 完全在用户空间实现的线程的优点是:创建和调度线程都无需内核的干预,因此速度相当快。并且由于它不占用额外的内核资源,所以即使一个进程创建了很多线程,也不会对系统性能造成明显的影响。其缺点是:对于多处理器系统

【Java并发工具类】ReadWriteLock

房东的猫 提交于 2020-02-19 17:55:16
摘自: https://www.cnblogs.com/myworld7/p/12323467.html 阅读目录 前言 什么是读写锁 ReentrantReadWriteLock 实现一个快速缓存 缓存数据的初始化 实现缓存的按需加载 读写锁的升级与降级 小结 回到目录 前言 前面介绍过 ReentrantLock ,它实现的是一种标准的互斥锁:每次最多只有一个线程能持有ReentrantLock。这是一种强硬的加锁规则,在某些场景下会限制并发性导致不必要的抑制性能。互斥是一种保守的加锁策略,虽然可以避免“写/写”冲突和“写/读”冲突,但是同样也避免了“读/读”冲突。 在读多写少的情况下,如果能够放宽加锁需求,允许多个执行读操作的线程同时访问数据结构,那么将提升程序的性能。只要每个线程都能确保读到最新的数据,并且在读取数据时不会有其他的线程修改数据,那么就不会发生问题。在这种情况下,就可以使用 读写锁 :一个资源可以被多个读操作访问,或者被一个写操作访问,但两者不能同时进行。 Java中读写锁的实现是 ReadWriteLock 。下面我们先介绍什么是读写锁,然后利用读写锁快速实现一个缓存,最后我们再来介绍读写锁的升级与降级。 回到目录 什么是读写锁 读写锁是一种性能优化措施,在读多写少场景下,能实现更高的并发性。读写锁的实现需要遵循以下三项基本原则: 允许多个线程同时读共享变量

linux进程间互斥锁和条件变量

Deadly 提交于 2020-02-19 00:12:16
设置进程间共享属性互斥锁和条件变量 将该互斥锁和条件变量放到共享内存中 public.h # ifndef _PUBLIC_H # define _PUBLIC_H # include <pthread.h> # include <string.h> # include <stdio.h> # include <stdlib.h> # include <unistd.h> # include <errno.h> # include <ctype.h> # include <sys/mman.h> # include <sys/stat.h> /* For mode constants */ # include <fcntl.h> /* For O_* constants */ typedef struct interaction { int id ; char name [ 8 ] ; pthread_cond_t cond ; pthread_mutex_t mutex ; } Interaction ; extern Interaction * get_interaction ( const char * filename ) ; # endif // _PUBLIC_H interaction.c #include "public.h" Interaction* get

两情侣之间容易形成什么锁?进来瞧瞧

夙愿已清 提交于 2020-02-12 21:08:07
文章目录 互斥锁 死锁 互斥锁 进程之间数据隔离,但是共享一套文件系统,因而可以通过文件来实现进程直接的通信,但问题是必须自己加锁处理。 注意:加锁的目的是为了保证多个进程修改同一块数据时,同一时间只能有一个修改,即串行的修改,没错,速度是慢了,牺牲了速度而保证了数据安全 那么也就是说当多个线程几乎同时修改一个共享数据的时候,需要进行同步控制,线程同步能够保证多个 线程安全的访问竞争资源(全局内容),最简单的同步机制就是使用互斥锁。 某个线程要更改共享数据时,先将其锁定,此时资源的状态为锁定状态,其他线程就能更 改,直到该线程将资源状态改为非锁定状态,也就是释放资源,其他的线程才能再次锁定资 源。互斥锁保证了每一次只有一个线程进入写入操作。从而保证了多线程下数据的安全性。 死锁 我献给大家介绍一些死锁:在多个线程共享资源的时候,如果两个线程分别占有一部分资源,并且同时等待对方的资 源,就会造成死锁现象。 我给大家举一个比较搞笑的例子 两情侣之间吵得不可开交你不让我我不让你,那么要是双方都不开口,那么双方是不是就是一直等待着 那我带大家来看一下死锁是怎样的结构: from threading import Lock from threading import Thread lock1=Lock() lock2=Lock() def work1(num): lock1.acquire(

synchronized

女生的网名这么多〃 提交于 2020-02-12 04:55:39
首先讲一下原子性以及互斥。 举个例子,在32位CPU上执行long(64位)变量的写操作时,会存在多线程下读写不一致的问题。 因为32位CPU下对其写会拆分成两次操作,一次写高32位和一次写底32位,而这个操作无法保证其 原子性 所以产生并发问题了。 原子性 指即一个操作或者多个操作,要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行,简单的说就是一个或者多个操作在 CPU 执行的过程中不被中断的特性。 互斥 如果 同一时刻只有一个线程执行 则被称之为 互斥 ,把一段需要互斥执行的代码称为 临界区 。如果我们能够保证对共享变量的修改是互斥的,那么,无论是单核 CPU 还是多核 CPU,就都能保证原子性了。 互斥锁 锁是一种通用的技术方案,Java 语言提供的 synchronized 关键字,就是一种互斥锁。synchronized 关键字可以用来修饰方法,也可以用来修饰代码块,通过其修饰的临界区是互斥的,使用方法如下: public class demo{ private final Object monitor = new Object(); // 修饰非静态方法 synchronized void method1() { // 临界区 } // 修饰静态方法 synchronized static void method2() { // 临界区 } // 修饰代码块

深入并发锁,解析Synchronized锁升级

六月ゝ 毕业季﹏ 提交于 2020-02-09 17:06:40
这篇文章分为六个部分,不同特性的锁分类,并发锁的不同设计,Synchronized中的锁升级,ReentrantLock和ReadWriteLock的应用,帮助你梳理 Java 并发锁及相关的操作。 一、锁有哪些分类 一般我们提到的锁有以下这些: 乐观锁/悲观锁 公平锁/非公平锁 可重入锁 独享锁/共享锁 互斥锁/读写锁 分段锁 偏向锁/轻量级锁/重量级锁 自旋锁 上面是很多锁的名词,这些分类并不是全是指锁的状态,有的指锁的特性,有的指锁的设计,下面分别说明。 1、乐观锁 VS 悲观锁 乐观锁与悲观锁是一种广义上的概念,体现了看待线程同步的不同角度,在Java和数据库中都有此概念对应的实际应用。 (1)乐观锁 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。 乐观锁适用于多读的应用类型,乐观锁在Java中是通过使用无锁编程来实现,最常采用的是CAS算法,Java原子类中的递增操作就通过CAS自旋实现的。 CAS全称 Compare And Swap(比较与交换),是一种无锁算法。在不使用锁(没有线程被阻塞)的情况下实现多线程之间的变量同步。java.util.concurrent包中的原子类就是通过CAS来实现了乐观锁。 简单来说,CAS算法有3个三个操作数:

java 锁机制

喜欢而已 提交于 2020-01-30 21:21:12
公平锁/非公平锁 可重入锁 独享锁/共享锁 互斥锁/读写锁 乐观锁/悲观锁(实现秒杀的一种解决方案) (select * from product p where p.type=’xxxxx’ for update) 分段锁 偏向锁/轻量级锁/重量级锁 自旋锁 这些分类并不是全是指锁的状态,有的指锁的特性,有的指锁的设计, 公平锁/非公平锁 公平锁是指多个线程按照申请锁的顺序来获取锁。 非公平锁是指多个线程获取锁的顺序并不按照申请锁的顺序,有可能后申请的线程比先申请的线程优先获取锁。有可能,会造成优先级反转或者饥饿现象。 对于Java ReentrantLock而言,通过构造函数指定该锁是否是公平锁,默认是非公平锁。非公平锁的优点在于吞吐量比公平锁大。 对于Synchronized而言,也是一种非公平锁。由于其并不像ReentrantLock是通过AQS的来实现线程调度,所以并没有任何办法使其变成公平锁。 AQS 的核心思想是,如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并将共享资源设置为锁定状态,如果被请求的共享资源被占用,那么就需要一套线程阻塞等待以及被唤醒时锁分配的机制,这个机制AQS是用CLH队列锁实现的,即将暂时获取不到锁的线程加入到队列中。 CLH (Craig,Landin,and Hagersten)队列是一个虚拟的双向队列

走进原子性

二次信任 提交于 2020-01-29 13:48:27
走进原子性 问题:线程之间的协作 标准解决方法:上锁 实现一个计数器和互斥锁 locking的问题 硬件同步的早期 Compare and Swap(CAS) 用CAS来实现计数器 lock-free和wait-free算法 原子变量类 细颗粒度意味着轻量级 十五年前,多核处理器是特别的系统,需要花费成百上千的美元。今天,多核处理器系统又便宜又丰富,几乎每一个主要的微处理器都对并发有内部支持。 为了利用好多核的优势,软件也架构在多线程上。但是,仅仅将一个工作简单地划分为几个线程并不能发挥出硬件的优势-----你必须要确保你的线程大部分时间是在工作,而不是在等待工作,或者是在共享数据结构上等锁。 问题:线程之间的协作 几乎没有task能够真正地并发运行,不需要线程之间的协作。想象一个线程池,那里tasks是互相独立地运行的。假如一个线程池要为一个queue工作,那么为queue加入或者删除元素都必须是线程安全的,那意味着在head,tail,或者内部node的引用之间的协作。正是这样的协作导致了所有的问题。 标准解决方法:上锁 对于共享字段的协作获取的传统做法是通过synchronize,它确保所有对共享字段的获取都是拿着锁的状态。使用synchronize,你可以确保不管哪个保护着一些变量的线程取得锁,它都会对这些变量有着独享,而对这些变量的改变又会变成可见的

Python进程、线程、协程之间的关系

喜你入骨 提交于 2020-01-28 15:22:27
一、从操作系统角度 操作系统处理任务, 调度单位是 进程 和 线程 。 1.进程: 表示一个程序的执行活动 (打开程序、读写程序数据、关闭程序) 2.线程: 执行某个程序时, 该进程调度的最小执行单位 (执行功能1,执行功能2) 一个程序至少有一个进程 一个进程至少有一个线程 1.并行: 需要处理的任务数 == CPU核心数量 两个任务 两个核心 任务1:------------- 任务2:------------- 2.并发: 需要处理的任务数 > CPU核心数量 三个任务 一个核心 任务1: ----- ------ 任务2: ------ 任务3: ------ 二、从程序角度 多进程和多线程 表示:当前程序可以同时执行多个任务 进程和线程都是由 操作系统调度完成 1.进程:    每个进程都是有自己独立的内存空间,不同进程之间的内存空间是不能共享。 不同进程之间的通信是由操作系统来完成的。 不同进程之间的通信效率低切换开销也大。 2.线程:   一个进程下可以有多个线程,同一个进程内的线程可以共享内存空间. 不同线程之间的通信 有进程 管理。 不同线程之间的通信效率高,切换开销小。 3.互斥锁:   共享意味着多个线程的竞争 会导致不安全问题。 为了保护内存空间的数据不被多个线程同时读写, 导致数据隐患, 于是诞生了" 互斥锁 "。 "互斥锁":