Java并发编程笔记—摘抄—基础知识
什么是线程安全
当多个线程访问某个类时,不管运行环境采用何种调度方式或者这些线程如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为,那么就称这个类是线程安全的。
竞态条件
当某个计算的正确性取决于多个线程的交替执行时序时,那么就会发生竞态条件。换句话说就是正确的结果取决于运气。
数据竞争
数据竞争是指,如果在访问非final类型的域时没有采用同步来进行协同,那么就会出现竞争。
重入
由于内置锁是可以重入的,因此如果某个线程试图获得一个已由它自己持有的锁,那么这个请求就会成功。“重入”意味着获取锁的操作的粒度是“线程”,不是“调用”。(这与pthread<POSIX线程>互斥体的默认加锁行为是不同,pthread互斥体的获取锁操作是以“调用”为粒度的)
用锁来保护状态
如果用同步锁来协调对某个变量的访问,那么子访问这个变量的所有位置上都需要使用同步。而且,当使用锁来协调某个变量的访问时,在访问变量的所有位置上都要使用同一个锁。
活跃性
安全性的含义是“永远不发生糟糕的事情”,而活跃性则关注于另一个目标,即“某件正确的事情最终会发生”。当某个操作无法继续执行下去时,就会发生活跃性问题。
当执行时间较长的计算或者可能无法快速完成的操作时(例如,网络I/O或控制台I/0),一定不要持有锁。
volatile变量
从内存可见性的角度来看,写入volatile变量相当于退出同步代码块,而读取volatile变量相当于进入同步代码块。
volatile变量的正确使用方式包括:确保它们自身状态的可见性,确保它们所有引用对象的状态可见性,以及标志一些重要的程序声明周期时间发生(例如,初始化或关闭)。
发布与逸出
“发布(Publish)”一个对象的意思是指,使对象能够在当前作用域之外的代码中使用。
当某个不应该发布的对象被发布时,这种情况称之为“逸出(Escape)”。
线程封闭
当访问共享的可变数据时,通常需要使用同步。一种避免使用同步的方式就是不共享数据,就不需要同步。这种技术称之为线程封闭(Thread Confinement),它是实现线程安全性的最简单方式之一。这种用法将自动实现线程安全性,即使被封闭的对象本身不是线程安全的。
线程封闭是在程序设计中考虑的一个因素,必须在程序中实现。维持线程封闭的一种更规范方法是使用ThreadLocal。
Ad-hoc线程封闭
Ad-hoc线程封闭是指,维护线程封闭性职责完全由程序实现来承担。
栈封闭
栈封闭是线程封闭的一个特例,在栈封闭中,只能通过局部变量才能访问对象。局部变量的固有属性之一就是封闭在执行线程中。在维持对象引用的栈封闭时,程序员需要多做一些工作以确保被引用的对象不会逸出。
(只有编写代码的开发人员才知道哪些对象需要被封闭到线程中,如果没有明确的文档说明,后期维护的人员很容易错误的使对象逸出)
不变性
如果某个对象在被创建后其状态就不能被修改,那么这个对象就称之为不可变对象。
不可变需求:状态不可修改,所有域都是final域,以及正确的构造过程。
Final域
在Java内存模型中,final域还有着特殊的语义。final域能确保初始化过程的安全性,从而可以不受限制地访问不可变对象,并在共享这些对象时无须同步。
事实不可变对象
如果对象从技术上来说是可变的,但其状态在发布后不会再改变,那么把这种对象称之为事实不可变对象(Effectively Immutable Object)。
不可变对象可以通过任意机制来发布
事实不可变对象必须通过安全方式发布。
可变对象必须通过方式发布,并且必须是线程安全的或者由某个锁保护起来。
并发程序中共享对象
线程封闭、只读共享、线程安全共享、保护对象。
客户端加锁机制
客户端加锁机制是指,对于使用某个对象X的客户端代码,使用X本身用于保护其状态的锁来这段客户端代码。要使用客户端加锁,你必须知道对象X使用的是哪一个锁。
闭锁
闭锁是一种同步工具类,可以延迟线程的进度直到其达到终止状态。
计数信号量
计数信号量用来控制同时访问某个特定资源的操作数量,或者同时执行某个指定操作的数量
二值信号量
二值信号量可以用作互斥体,并具备不可重入的加锁语义:谁拥有这个唯一的许可,谁就拥有了互斥锁。
栅栏
栅栏类似于闭锁,它能组织一组线程直到某个事件发生。栅栏与闭锁的关键区别在于,所有线程必须同时到达栅栏的位置,才能继续执行。闭锁用于等待事件,而栅栏用于等待其他线程。
Exchanger栅栏
这是一种两方栅栏,各方在栅栏位置交换数据,当两方执行不对称操作时,Exchanger会非常有用,例如当一个线程向缓冲区写入数据,而另一个线程从缓冲区读取数据。
缓存导致性能瓶颈转移
简单的缓存可能会将性能的瓶颈转变成可伸缩性瓶颈,即使缓存用于提升单单线程的性能。
总结:
- 可变状态是至关重要的。
- 尽量将域声明为final类型,除非需要它们是可变的。
- 不可变对象一定是线程安全的。
- 封装有助于管理复杂性。
- 用锁来保护每个可变变量。
- 当保护同一个不变性条件中的所有变量时,要使用同一个锁。
- 在执行符合操作期间,要持有锁。
- 如果多个线程中访问同一个可变变量时没有同步机制,那么程序会出先问题。
- 不要故作聪明的推断出不需要使用同步。
- 在设计过程中考虑线程安全,或者在文档中明确的指出它不是线程安全的。
- 将同步策略文档化。
Java并发编程笔记—摘抄—基础知识的更多相关文章
- Java并发编程笔记之基础总结(二)
一.线程中断 Java 中线程中断是一种线程间协作模式,通过设置线程的中断标志并不能直接终止该线程的执行,而是需要被中断的线程根据中断状态自行处理. 1.void interrupt() 方法:中断线 ...
- Java并发编程笔记之基础总结(一)
一.线程概念 说到线程就必须要提一下进程,因为线程是进程中的一个实体,线程本身是不会独立存在的.进程是代码在数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,线程则是进程的一个执行路径,一 ...
- java并发编程笔记(十一)——高并发处理思路和手段
java并发编程笔记(十一)--高并发处理思路和手段 扩容 垂直扩容(纵向扩展):提高系统部件能力 水平扩容(横向扩容):增加更多系统成员来实现 缓存 缓存特征 命中率:命中数/(命中数+没有命中数) ...
- java并发编程笔记(六)——AQS
java并发编程笔记(六)--AQS 使用了Node实现FIFO(first in first out)队列,可以用于构建锁或者其他同步装置的基础框架 利用了一个int类型表示状态 使用方法是继承 子 ...
- java并发编程笔记(十)——HashMap与ConcurrentHashMap
java并发编程笔记(十)--HashMap与ConcurrentHashMap HashMap参数 有两个参数影响他的性能 初始容量(默认为16) 加载因子(默认是0.75) HashMap寻址方式 ...
- java并发编程笔记(九)——多线程并发最佳实践
java并发编程笔记(九)--多线程并发最佳实践 使用本地变量 使用不可变类 最小化锁的作用域范围 使用线程池Executor,而不是直接new Thread执行 宁可使用同步也不要使用线程的wait ...
- java并发编程笔记(八)——死锁
java并发编程笔记(八)--死锁 死锁发生的必要条件 互斥条件 进程对分配到的资源进行排他性的使用,即在一段时间内只能由一个进程使用,如果有其他进程在请求,只能等待. 请求和保持条件 进程已经保持了 ...
- java并发编程笔记(七)——线程池
java并发编程笔记(七)--线程池 new Thread弊端 每次new Thread新建对象,性能差 线程缺乏统一管理,可能无限制的新建线程,相互竞争,有可能占用过多系统资源导致死机或者OOM 缺 ...
- java并发编程笔记(五)——线程安全策略
java并发编程笔记(五)--线程安全策略 不可变得对象 不可变对象需要满足的条件 对象创建以后其状态就不能修改 对象所有的域都是final类型 对象是正确创建的(在对象创建期间,this引用没有逸出 ...
随机推荐
- [CoreOS 转载] CoreOS实践指南(三):系统服务管家Systemd
转载:http://www.csdn.net/article/2015-01-08/2823477 摘要:CoreOS是采用了高度精简的系统内核及外围定制的操作系统.ThoughtWorks的软件工程 ...
- 【论文笔记】多任务学习(Multi-Task Learning)
1. 前言 多任务学习(Multi-task learning)是和单任务学习(single-task learning)相对的一种机器学习方法.在机器学习领域,标准的算法理论是一次学习一个任务,也就 ...
- java多线程20 : ReentrantLock中的方法 ,公平锁和非公平锁
公平锁与非公平锁 ReentrantLock有一个很大的特点,就是可以指定锁是公平锁还是非公平锁,公平锁表示线程获取锁的顺序是按照线程排队的顺序来分配的,而非公平锁就是一种获取锁的抢占机制,是随机获得 ...
- Java操作memcache
[本文出自天外归云的博客园] 准备工作 Java操作memcache需要spymemcache类库的支持,在Eclipse中修改maven项目的pom.xml文件—— 添加仓库: <reposi ...
- Oracle用户密码过期的处理方法
受影响版本:Oracle11g以上版本. 导致密码消失的原因:Oracle 11g中默认的DEFAULT概要文件中口令有效期PASSWORD_LIFE_TIME默认值为180天. 当以客户端登 ...
- Android 桌面Widget开发要点(时间日期Widget)
最近需要编写一个日期时间的桌面Widget用来关联日历程序,以前很少写桌面Widget.对这方面技术不是很熟悉,今天花时间重新整理了一下,顺便把编写一个简单时间日期程序过程记录下来. 桌面Widget ...
- WebAPI Action的几种返回值类型
void 返回204状态码 HttpResponseMessage Convert directly to an HTTP response message. IHttpActionResult Ca ...
- OAuth2.0 授权的工作原理
作者:Barret李靖链接:https://www.zhihu.com/question/19781476/answer/81020455来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业 ...
- 快速排序,一个爱情故事-java版
public static void myquicksort(int[] ages,int girl,int boy){ //这是一个站在数组两端,追求完美爱情的故事 //年龄不匹配的不要 //第0步 ...
- 几种经典的Hash算法的实现(源代码)
来源声明: http://blog.minidx.com/2008/01/27/446.html 先保存下来,以备后面研究,现在还看不懂! 哈希算法将任意长度的二进制值映射为固定长度的较小二进制值,这 ...