线程安全

Java并发编程:synchronized

寵の児 提交于 2019-12-07 21:37:44
原文出处: 海子 虽然多线程编程极大地提高了效率,但是也会带来一定的隐患。比如说两个线程同时往一个数据库表中插入不重复的数据,就可能会导致数据库中插入了相同的数据。今天我们就来一起讨论下线程安全问题,以及Java中提供了什么机制来解决线程安全问题。 以下是本文的目录大纲: 一.什么时候会出现线程安全问题? 二.如何解决线程安全问题? 三.synchronized同步方法或者同步块 若有不正之处,请多多谅解并欢迎批评指正。 一.什么时候会出现线程安全问题? 在单线程中不会出现线程安全问题,而在多线程编程中,有可能会出现同时访问同一个资源的情况,这种资源可以是各种类型的的资源:一个变量、一个对象、一个文件、一个数据库表等,而当多个线程同时访问同一个资源的时候,就会存在一个问题: 由于每个线程执行的过程是不可控的,所以很可能导致最终的结果与实际上的愿望相违背或者直接导致程序出错。 举个简单的例子: 现在有两个线程分别从网络上读取数据,然后插入一张数据库表中,要求不能插入重复的数据。 那么必然在插入数据的过程中存在两个操作: 1)检查数据库中是否存在该条数据; 2)如果存在,则不插入;如果不存在,则插入到数据库中。 假如两个线程分别用thread-1和thread-2表示,某一时刻,thread-1和thread-2都读取到了数据X,那么可能会发生这种情况: thread

.NET进阶篇06-async异步、thread多线程4

邮差的信 提交于 2019-12-07 15:22:29
知识需要不断积累、总结和沉淀,思考和写作是成长的催化剂 梯子 一、锁 1、lock 2、Interlocked 3、Monitor 4、SpinLock 5、Mutex 6、Semaphore 7、Events 1、AutoResetEvent 2、ManualResetEvent 3、ManualResetEventSlim 8、ReaderWriterLock 二、线程安全集合 三、多线程模型 1、同步编程模型SPM 2、异步编程模型APM 3、基于事件编程模型EAP 4、基于任务编程模型TAP 四、End 一、锁 数据库中也有锁概念,行锁,表锁,事物锁等,锁的作用就是 控制并发情况下数据的安全一致 ,使一个数据被操作时,其他并发线程等待。开发方面多线程并行编程访问共享数据时,为保证数据的一致安全,有时需要使用锁来锁定对象来达到同步 .NET中提供很多线程同步技术。有lock,Interlocked,Monitor等用于进程内同步锁,Mutex互斥锁,Semaphore信号量,Events,ReaderWriterLockSlim读写锁等用于多个进程间的线程同步 1、lock lock语句是设置对锁定和解除锁定的一种简单方式,也是最常用的一种同步方式。lock用于锁定一个 引用类型字段 ,当线程执行到Lock处,会锁定该字段,使之只有一个线程进入lock语句块内

GCD之同步锁和派发队列

你说的曾经没有我的故事 提交于 2019-12-07 15:19:44
在OC中,如果有多个线程要执行同一份代码,那么就可能会出现问题.(比如出现读写不一致的情况)这种情况下通常需要使用锁来实现某种同步机制.在GCD 出现之前,有两种办法,第一种是使用内置的同步块 synchronization block - (void)synchronizedMethod { @synchronized(self) { // } } 这种写法会根据给定的对象自动创建一个锁,并等到块中的代码执行完毕.执行到代码结尾处,锁就会自动释放. 需要注意的是:滥用@synchronized(self)会降低代码的执行效率,因为公用一个锁的那些同步块必须按照顺序执行.若是在self上频繁加锁,那么程序可能要等待另一段无关的代码执行完毕才能继续执行当前的代码. 另一方法是直接使用 NSLock对象. _lock = [[NSLock alloc] init]; - (void)synchronizedMethod_lock { [_lock lock]; // safe [_lock unlock]; } 这两种方法都很好,但是也有缺陷.比如:极端情况下,同步块会导致死锁,而且性能也不见得高效,而如果直接使用锁对象的话,一旦遇上死锁将会非常难处理. 替代方案就是使用GCD,他能以更简单 更高效的形式为代码加锁. 比如说属性就是开发者经常需要同步的地方,这种属性需要做成原子的 .

Signal处理中的函数可重入问题

偶尔善良 提交于 2019-12-07 07:44:05
1. Signal信号简介 信号是软件层次上模拟的中断,它是一种异步通信的处理机制。信号的异步性意味着,应用程序不用等待事件的发生,当信号发生时应用程序自动陷入到对应的信号处理函数中。产生信号的事件对进程而言是随机出现的。信号的响应方式有忽略、捕捉、执行默认动作三种。 2. 线程安全 线程安全函数:在C语言中局部变量是在栈中分配的,任何未使用静态数据或其他共享资源的函数都是线程安全的。使用全局变量的函数是非线程安全的。使用静态数据或其他共享资源的函数,必须通过加锁的方式来使函数实现线程安全。 线程安全的(Thread-Safe):如果一个函数在同一时刻可以被多个线程安全地调用,就称该函数是线程安全的。线程安全函数解决多个线程调用函数时访问共享资源的冲突问题。 3. 可重入 可重入(Reentrant)函数可以由多于一个线程并发使用,而不必担心数据错误。可重入函数可以在任意时刻被中断,稍后再继续运行,不会丢失数据。可重入性解决函数运行结果的确定性和可重复性。 1) 一个函数对于多个线程是可重入的,则这个函数是线程安全的; 2) 一个函数是线程安全的,但并不一定是可重入的,比如使用互斥锁实现的线程安全; 3) 可重入性要强于线程安全性。 4. Signal信号处理 信号处理函数中只能调用可重入函数,而不能调用不可重入函数。进程捕捉到信号并对其进行处理时

Java基础学习笔记-Collection

孤者浪人 提交于 2019-12-07 00:15:41
Collection ArrayList: 动态数组 LinkedList: 双向链表 Vector: 动态数组、线程安全 Stack: 继承Vector,动态数组,FILO HashMap: table为数组,entry为链表 HashTable: 线程安全,类似于HashMap(很少使用) WeakHashMap: ConurrentHashMap: TreeMap: 红黑树、有序、可序列化 HashSet:唯一、无序、非线程安全 TreeSet:继承TreeMap,有序、支持序列化 根据 Java 集合系列目录(Category) 总结而成,感谢原作者的贡献。 来源: oschina 链接: https://my.oschina.net/u/3569587/blog/1632337

Java Concurrency

心不动则不痛 提交于 2019-12-06 23:21:26
1.简介 2.线程安全性 2.1什么是线程安全性 3.对象的共享 4.对象的组合 4.1设计线程安全的类 4.2实例封闭 本文参考《Java Concurrency in Practice》。 1.简介 编写正确的进程很难,而编写正确的并发进程则难上加难。 2.线程安全性 要编写线程安全的代码,核心在于要对状态访问操作进行管理,特别是对共享(Shared)和可变(Mutable)状态的访问。从非正式意义上来说,对象的状态是指存储在状态变量(例如实例或静态域)中的数据。对象的状态可能包括其他依赖对象的域。 在对象的状态中 包含了任何可能影响其外部可见行为的数据 。 共享 意味着变量可以由多个线程同时访问,而 可变 则意味着变量的值在其生命周期内可以发生变化。一个对象是否需要是线程安全的,取决于它是否被多个线程访问。要使得对象是线程安全的,需要采用同步机制来协同对对象可变状态的访问。如果无法实现协同,那么可能会导致数据破坏以及其他不该出现的结果。 当多个线程访问某个状态变量并且其中有一个线程执行写入操作时,必须采用同步机制来协同这些线程对变量的访问。Java中的主要同步机制是关键字 synchronized ,它提供了一种独占的加锁方式,但“同步”这个术语还包括volatile类型的变量,显示锁(Explicit Lock)以及原子变量。

如何设计线程安全的Java程序

走远了吗. 提交于 2019-12-06 20:02:03
什么是线程安全的(thread-safe)? 在java中,线程安全的指的是代码可以在并发的或者多线程的环境下安全的使用或者共享,并且它们都将按照期望的方式运行。任何代码,类或者对象,如果它们在并发的环境中运行表现出的行为与在非并发环境下表现出的行为不一致,那么它们就不能被称为线程安全的。 本片文章不会非常仔细的介绍线程安全或者Java中的异步处理,我们将通过几个例子来帮助你理解什么是线程安全的然后告诉你如何让你的代码线程安全。 一个non-thread-safe的例子 public class Counter { private int count; /* * 这个方法不是线程安全的,因为++操作不是原子操作 */ public int getCount(){ return count++; } } 上面的例子不是线程安全的,因为++(自增操作)不是一个原子操作(atomic operation),而是会被拆分成读、更新和写操作(read,update,write)三部分,如果多个线程大约在同一时刻调用getCount()方法,这三个操作可能会互相重合(coincide)或者重叠(overlap),比如:当thread1正在更新数据,thread2此时读取数据,那他将会获得原来的旧数据,最后的结果就是thread2会覆盖掉thread1对数据的增加操作,结果就是:一个数据被丢失了

Java并发多线程面试题 Top 50

吃可爱长大的小学妹 提交于 2019-12-06 14:36:22
不管你是新程序员还是老手,你一定在面试中遇到过有关线程的问题。Java语言一个重要的特点就是内置了对并发的支持,让Java大受企业和程序员的欢迎。大多数待遇丰厚的Java开发职位都要求开发者精通多线程技术并且有丰富的Java程序开发、调试、优化经验,所以线程相关的问题在面试中经常会被提到。 在典型的Java面试中, 面试官会从线程的基本概念问起, 如:为什么你需要使用线程, 如何创建线程,用什么方式创建线程比较好(比如: 继承thread类还是调用Runnable接口 ),然后逐渐问到并发问题像在Java并发编程的过程中遇到了什么挑战,Java内存模型,JDK1.5引入了哪些更高阶的并发工具,并发编程常用的 设计模式 ,经典多线程问题如生产者消费者,哲学家就餐,读写器或者简单的有界缓冲区问题。仅仅知道线程的基本概念是远远不够的, 你必须知道如何处理 死锁 , 竞态条件 ,内存冲突和线程安全等并发问题。掌握了这些技巧,你就可以轻松应对多线程和并发面试了。 许多Java程序员在面试前才会去看面试题,这很正常。因为收集面试题和练习很花时间,所以我从许多面试者那里收集了Java多线程和并发相关的50个热门问题。我只收集了比较新的面试题且没有提供全部答案。想必聪明的你对这些问题早就心中有数了, 如果遇到不懂的问题,你可以用Google找到答案。若你实在找不到答案,可以在文章的评论中向我求助

volatile

北战南征 提交于 2019-12-06 14:34:53
Java 语言中的 volatile 变量可以被看作是一种 “程度较轻的 synchronized ”;与 synchronized 块相比,volatile 变量所需的编码较少,并且运行时开销也较少,但是它所能实现的功能也仅是 synchronized 的一部分。本文介绍了几种有效使用 volatile 变量的模式,并强调了几种不适合使用 volatile 变量的情形。 锁提供了两种主要特性: 互斥(mutual exclusion) 和 可见性(visibility) 。互斥即一次只允许一个线程持有某个特定的锁,因此可使用该特性实现对共享数据的协调访问协议,这样,一次就只有一个线程能够使用该共享数据。可见性要更加复杂一些,它必须确保释放锁之前对共享数据做出的更改对于随后获得该锁的另一个线程是可见的 —— 如果没有同步机制提供的这种可见性保证,线程看到的共享变量可能是修改前的值或不一致的值,这将引发许多严重问题。 Volatile 变量 Volatile 变量具有 synchronized 的可见性特性,但是不具备原子特性。这就是说线程能够自动发现 volatile 变量的最新值。Volatile 变量可用于提供线程安全,但是只能应用于非常有限的一组用例:多个变量之间或者某个变量的当前值与修改后值之间没有约束。因此,单独使用 volatile 还不足以实现计数器

26 多线程(六)——线程安全 synchronized

北城余情 提交于 2019-12-06 14:00:58
关键字synchronized可以写在方法和代码块中 写在普通方法中:锁住的对象时this 写在静态方法中:锁住的对象时class 写在代码块中 关于这个synchronized关键字 线程锁会造成性能下降 线程锁用在大的方法中,很影响性能 关于线程锁 除了使用synchronized关键字外,还可以使用另一种线程锁,本文没有收录方法 下面来看一个没有加线程锁的案例:3个线程抢票 package _20191205; /** * 线程不安全: * @author TEDU */ public class SynTest01 { public static void main(String[] args) { //一份资源 SafeWeb12306 web = new SafeWeb12306(); new Thread(web,"线程1").start(); new Thread(web,"线程2").start(); new Thread(web,"线程3").start(); } } class SafeWeb12306 implements Runnable{ //票数 private int ticketNums = 100; private boolean flag = true; @Override public void run() { while(flag) {