互斥锁

java数据结构类--笔记

谁都会走 提交于 2019-12-20 04:12:32
程序的灵魂是算法。提到算法,肯定离不开数据结构。今天就聊一聊java中的和数据结构相关的类。 java.util包 concurrent包 里面是和并发编程相关的类 主要是:原子类–锁--并发的数据结构类【队列,链表,哈希…】 atomic—原子类【 https://blog.csdn.net/boom_man/article/details/78352722 】 locks—锁 Lock锁和同步块的区别 1.同步块只能包含在一个方法内----而lock()和unlock()操作却可以在跨越多个不同的方法使用。 2.同步块不支持公平性,任一个线程都能获取已经被释放的锁,不能指定优先权。但我们却可以使用Lock API指定公平属性从而实现公平性。它能确保等待时间最长的线程优先获取锁。 3.当一个线程不能访问同步块时,它会被阻塞住。而 Lock API提供的有 tryLock()方法,使用该方法,只有在锁不被其他线程持有且可用时,才会真正获取锁。这将极大地降低阻塞时间。 4.那些获取访问同步块的等待线程不能被中断,Lock API提供了一个 lockInterruptbly()方法,当线程正在等待锁时,该方法可以用于中断该线程。’ 接口 ReadWriteLock读写锁 ReadWriteLock维护一对关联锁,一个用于只读操作,一个用于写入。只要没有写入程序

026 UNIX再学习 -- 线程同步

六月ゝ 毕业季﹏ 提交于 2019-12-18 22:05:52
一、为什么要线程同步 当多个控制线程共享相同的内存时,需要确保每个线程看到一致的数据视图。如果每个线程使用的变量都是其他线程不会读取和修改的,那么就不存在一致性问题。同样,如果变量时只读的,每个线程同时读取该变量也不会有一致性问题。但是, 当一个线程可以修改的变量,其他线程也可以读取或者修改的时候,我们就需要对这些线程进行同步,确保它们在访问变量的存储内容时不会访问到无效的值 。 当一个线程修改变量时,其他线程在读取这个变量时可能会看到一个不一致的值。在变量修改时间多于一个存储器访问周期的处理器结构中,当存储器读与存储器写这两个周期交叉时,这种不一致就会出现。当然,这种行为是与处理器体系结构相关的,但是可移植的程序并不能对使用何种处理器体系结构做出任何假设。 上图中描述了两个线程读写相同变量的假设例子。在这个例子中,线程 A 读取变量然后给这个变量赋予一个新的数值,但写操作需要两个存储器周期。当线程 B 在这两个存储器写周期中间读取这个变量时,它就会得到不一致的值。 为了解决这个问题,线程不得不使用锁,同一时间只允许一个线程访问该变量。 如果线程 B 希望读取变量,它首先要获取锁。同样,当线程 A 更新变量时,也需要获取同样的这把锁。这样,线程 B 在线程 A 释放锁以前就不能读取变量。 总结一下, 多线程共享进程中的资源,多个线程同时访问相同的共享资源时,需要相互协调

自旋锁与互斥锁

百般思念 提交于 2019-12-18 18:10:11
自旋锁(spinlock)与互斥锁(mutex)是并发编程中两个重要的概念。它们的主要作用是:对共享资源加锁以阻止数据的并发访问,从而保证数据一致性。但是它们也有一些不同点。本文主要介绍这些不同点,并说明我们什么时候该用自旋锁,什么时候该用互斥锁。 理论基础 理论上,当一个线程尝试去获取一个互斥锁,但由于该互斥锁已经被其它线程获取而没有成功时,它会立刻进入休眠状态,从而让出CPU时间,允许其它线程运行。它将持续休眠直到最终被唤醒,唤醒的条件是之前获取到该互斥锁的线程释放了互斥锁; 对比一下,当一个线程尝试去获取一个自旋锁,但由于该自旋锁已经被其它线程获取而没有成功时, 它将会反复获取它(在英文中叫polling),直到最终成功。因此在获取自旋锁的时候,该线程不会让出CPU时间,其它线程将不能运行,当然,操作系统不会允许一个线程一直阻塞整个系统的运行,在某个线程花完了它的CPU运行总时间后,它会强制切换到另外线程执行。(注:线程一次使用的CPU总时间的最大上限可以通过ulimit -t查看,单位为秒) 问题 对于互斥锁,使线程进入休眠以及唤醒线程都是比较昂贵的操作,需要相当多的CPU指令,花费较长的CPU时间。如果A线程获取到该互斥锁后,只是持有了很短的一段时间就释放,那么B线程在获取互斥锁的过程中,B线程进入休眠以及被唤醒花费的CPU时间可能超过了B线程休眠的时间

Java 多线程之自旋锁

不羁的心 提交于 2019-12-17 15:17:08
一、什么是自旋锁? 自旋锁(spinlock):是指当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环。 获取锁的线程一直处于活跃状态,但是并没有执行任何有效的任务,使用这种锁会造成 busy-waiting 。 它是为实现保护共享资源而提出一种锁机制。其实,自旋锁与互斥锁比较类似,它们都是为了解决对某项资源的互斥使用。无论是互斥锁,还是自旋锁,在任何时刻,最多只能有一个保持者,也就说,在任何时刻最多只能有一个执行单元获得锁。但是两者在调度机制上略有不同。对于互斥锁,如果资源已经被占用,资源申请者只能进入睡眠状态。但是自旋锁不会引起调用者睡眠,如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁,”自旋”一词就是因此而得名。 二、Java如何实现自旋锁? 下面是个简单的例子: public class SpinLock { private AtomicReference<Thread> cas = new AtomicReference<Thread>(); public void lock() { Thread current = Thread.currentThread(); // 利用CAS while (!cas.compareAndSet(null,

编程小知识之 虚假唤醒(spurious wakeup)

此生再无相见时 提交于 2019-12-17 08:36:52
本文简单介绍了一些 虚假唤醒(spurious wakeup) 相关的知识 (注: 本文假设读者对多线程开发有一定了解) 高层次的多线程编程中, 条件变量 是个常见的同步方法,跟传统仅使用 互斥量 的方法相比,条件变量可以减少锁的竞争. 拿 Pthread 举例,一个常见的条件变量的使用示例大概是这个样子的: // flag for sync bool g_signaled = false; pthread_mutex_t g_mutex; pthread_cond_t g_cond; // wait method void wait() { pthread_mutex_lock(&g_mutex); while (!g_signaled) { pthread_cond_wait(&g_cond, &g_mutex); } g_signaled = false; pthread_mutex_unlock(&g_mutex); } // signal method void signal() { pthread_mutex_lock(&g_mutex); g_signaled = true; pthread_mutex_unlock(&g_mutex); pthread_cond_signal(&g_cond); } 代码中调用的 pthread_cond_wait 方法

Java线程机制

落花浮王杯 提交于 2019-12-17 08:35:25
线程简介: 线程是一个程序内部的顺序控制流。 线程和进程的区别:   每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销。   线程可以看成是轻量级的进程,同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器,线程切换的开销小。 多进程:   在操作系统中能同时运行的多个任务。 多线程:   在同一个应用程序中有多个顺序流同时执行。 Java的线程是通过java.lang.Thread类实现的;JVM启动时会有一个由主方法所定义的线程;可以通过创建Thread的实例来创建新的线程;每个线程都是通过某个特定的Thread对象所对应的run()方法来完成其操作的,run()方法称为线程体。 线程的创建与启动: 第一种:   1.定义线程类target实现Runnable接口(使用Runnable接口可以为多个线程提供共享数据),其中Runnable中只有一个方法public void run();   2.Thread my Thread = new Thread(target);   3.在实现Runnable接口的类的run()方法定义中可以使用Thread的静态方法(currectThread()方法用于获取当前线程的引用)。 第二种:   1.可以定义一个Thread的子类并重写其run()方法:class MyThread extends

多线程环境使用fork调用

隐身守侯 提交于 2019-12-14 12:15:54
文章目录 1、多线程中使用fork存在隐患! 1.1、考虑问题 1.2、读者问题 2、线程中fork 须慎用! 3、推荐链接 1、多线程中使用fork存在隐患! 参考下图: 左侧------进程包含主线程,线程A,线程B三个线程以及一个全局互斥锁变量 右侧------线程B通过fork创建一个新的进程,新的进程在虚拟地址空间和左侧的进程空间完全一致(拷贝一份),并且只有一个主线程 1.1、考虑问题 问题情形: 第一步、 左侧的线程A/线程B/主线程当中 任意一个线程在线程B fork之前对互斥锁有Lock操作,前面已经强调了,fork产生的新进程是对父进程地址空间的拷贝 第二步、左侧进程空间互斥锁的lock状态通过fork函数,造成右侧进程得到的互斥锁为lock状态 第三步、右侧主线程在 不知情 的情况下,对互斥锁加锁,意外发生了,右侧线程会阻塞! 代码示例: // An highlighted block var foo = 'bar' ; 1.2、读者问题 乐于思考问题的朋友们可能会发问,这个情况我们可以通过多写两行代码避免吧? 自然可以! 诀窍在于:子进程在开始的时候解锁! 下图有个不可不提的地方,线程B在fork之前应当对mutex加锁。 笔者认为主要原因是需要设置mutex为一个明确的状态:Locked

你说的曾经没有我的故事 提交于 2019-12-13 21:32:15
使用synchronized获取互斥锁的几点说明 原文链接:https://blog.csdn.net/ns_code/article/details/17199201 采用synchronized修饰符实现的同步机制叫做互斥锁机制,它所获得的锁叫做互斥锁。每个对象都有一个monitor(锁标记),当线程拥有这个锁标记时才能访问这个资源,没有锁标记便进入锁池。任何一个对象系统都会为其创建一个互斥锁,这个锁是为了分配给线程的,防止打断原子操作。每个对象的锁只能分配给一个线程,因此叫做互斥锁。 1、如果同一个方法内同时有两个或更多线程,则每个线程有自己的局部变量拷贝。 2、类的每个实例都有自己的对象级别锁。当一个线程访问实例对象中的synchronized同步代码块或同步方法时,该线程便获取了该实例的对象级别锁,其他线程这时如果要访问synchronized同步代码块或同步方法,便需要阻塞等待,直到前面的线程从同步代码块或方法中退出,释放掉了该对象级别锁。 3、访问同一个类的不同实例对象中的同步代码块,不存在阻塞等待获取对象锁的问题,因为它们获取的是各自实例的对象级别锁,相互之间没有影响。 4、持有一个对象级别锁不会阻止该线程被交换出来,也不会阻塞其他线程访问同一示例对象中的非synchronized代码。当一个线程A持有一个对象级别锁

python基础-并发编程02

筅森魡賤 提交于 2019-12-10 14:29:59
并发编程 子进程回收的两种方式 join() 让主进程等待子进程结束,并回收子进程资源,主进程再结束并回收资源 from multiprocessing import Process import time def task(name): print(f'子进程{name}:starting……') time.sleep(1) print(f'子进程{name}:end……') if __name__ == '__main__': print('进入主进程……') pro_list = [] for i in range(3): pro_obj = Process(target=task, args=(i,)) pro_list.append(pro_obj) pro_obj.start() for pro in pro_list: # 强制子进程结束后,主进程才可以结束,实现子进程资源回收 pro.join() print('结束主进程……') 主进程正常结束 ,子进程与主进程一并被回收资源 了解知识 僵尸进程: 子进程结束后,主进程没有正常结束 ,子进程PID不会被回收。 缺点:操作系统中的PID号是有限的,只用PID号也就是资源被占用,可能会导致无法创建新的进程 孤儿进程: 子进程未结束,主进程没有正常结束 ,子进程PID不会被回收,会被操作系统优化机制回收。

线程安全

╄→гoц情女王★ 提交于 2019-12-10 14:22:13
在这三篇文章中,我将详细介绍原理操作,内存障碍和线程之间数据的快速交换,以及“sequence-points”示例中的“execute-around-idiom”。同时,我们将尝试一起做一些有用的事情。 标准C ++库中没有线程安全的容器(数组,列表,映射…),可以在多个线程中使用它们而无需附加锁。在使用标准容器进行多线程交换的情况下,可能会忘记使用互斥锁保护其中一个代码段,或者错误地使用另一个互斥锁来保护它。 显然,如果开发人员使用自己的解决方案而不是标准的解决方案,则会犯更多的错误。而且,如果任务很复杂,以至于没有任何标准解决方案,那么开发人员在尝试寻找解决方案时将充满错误。 依靠“实践大于理论”的原则,我们将努力创造出一个解决这个问题的最佳方法,而不是纸上谈兵。 在本文中,我们将实现使所有对象成为线程安全对象的智能指针,其性能与优化的无锁容器相同。 使用此类指针的简化,非优化示例: int main() {   contfree_safe_ptr< std::map< std::string, int > > safe_map_string_int;   std::thread t1( & { safe_map_string_int->emplace(“apple”, 1); });   std::thread t2( & { safe_map_string_int-