volatile是一个特殊的修饰符,只有成员变量才能使用它。java
在Java并发程序缺乏同步类的状况下,多线程对成员变量的操做对其它线程是透明的。安全
volatile变量能够保证下一个读取操做会在前一个写操做以后发生。多线程
首先,volatile 变量和 atomic 变量看起来很像,但功能却不同。架构
Volatile变量能够确保先行关系,即写操做会发生在后续的读操做以前, 但它并不能保证原子性。例如用volatile修饰count变量那么 count++ 操做就不是原子性的。并发
而AtomicInteger类提供的atomic方法可让这种操做具备原子性如getAndIncrement()方法会原子性的进行增量操做把当前值加一,其它数据类型和引用变量也能够进行类似操做。dom
同步集合与并发集合都为多线程和并发提供了合适的线程安全的集合,不过并发集合的可扩展性更高。异步
Java5介绍了并发集合像ConcurrentHashMap,不只提供线程安全还用锁分离和内部分区等现代技术提升了可扩展性。函数
Vector 是用同步方法来实现线程安全的工具
通常而言,读写锁是用来提高并发程序性能的锁分离技术的成果。性能
Java中的ReadWriteLock是Java 5 中新增的一个接口,一个ReadWriteLock维护一对关联的锁,一个用于只读操做一个用于写。在没有写线程的状况下一个读锁可能会同时被多个读线程持有。写锁是独占的,你可使用JDK中的ReentrantReadWriteLock来实现这个规则,它最多支持65535个写锁和65535个读锁。
在Java并发程序中FutureTask表示一个能够取消的异步运算。
它有启动和取消运算、查询运算是否完成和取回运算结果等方法。只有当运算完成的时候结果才能取回,若是运算还没有完成get方法将会阻塞。一个FutureTask对象能够对调用了Callable和Runnable的对象进行包装,因为FutureTask也是调用了Runnable接口因此它能够提交给Executor来执行。
ThreadLocal是Java里一种特殊的变量。
每一个线程都有一个ThreadLocal就是每一个线程都拥有了本身独立的一个变量,竞争条件被完全消除了。它是为建立代价高昂的对象获取线程安全的好方法,好比你能够用ThreadLocal让SimpleDateFormat变成线程安全的,由于那个类建立代价高昂且每次调用都须要建立不一样的实例因此不值得在局部范围使用它,若是为每一个线程提供一个本身独有的变量拷贝,将大大提升效率。
首先,经过复用减小了代价高昂的对象的建立个数。 其次,你在没有使用高代价的同步或者不变性的状况下得到了线程安全。
线程局部变量的另外一个不错的例子是ThreadLocalRandom类,它在多线程环境中减小了建立代价高昂的Random对象的个数。
线程转储是一个JVM活动线程的列表,它对于分析系统瓶颈和死锁很是有用。
有不少方法能够获取线程转储——使用Profiler,Kill-3命令,jstack工具等等。有的更喜欢jstack工具,由于它容易使用而且是JDK自带的。因为它是一个基于终端的工具,因此能够编写一些脚本去定时的产生线程转储以待分析。
若是你使用的LinkedBlockingQueue,也就是无界队列的话,不要紧,继续添加任务到阻塞队列中等待执行,由于LinkedBlockingQueue能够近乎认为是一个无穷大的队列,能够无限存听任务;
若是你使用的是有界队列比方说ArrayBlockingQueue的话,任务首先会被添加到ArrayBlockingQueue中,ArrayBlockingQueue满了,则会使用拒绝策略RejectedExecutionHandler处理满了的任务,默认是AbortPolicy。
当线程间是能够共享资源时,线程间通讯是协调它们的重要的手段。
Object类中wait()notify()notifyAll()方法能够用于线程间通讯关于资源的锁的状态。
Thread类提供了一个holdsLock(Object obj)方法,当且仅当对象obj的监视器被某条线程持有的时候,才会返回true.注意这是一个static方法,这意味着”某条线程”指的是当前线程。
死锁是指两个或两个以上的进程在执行过程当中,因争夺资源而形成的一种互相等待的现象,若无外力做用,它们都将没法推动下去。
一、自旋锁 二、自旋锁的其余种类 三、阻塞锁 四、可重入锁 五、读写锁 六、互斥锁 七、悲观锁 八、乐观锁 九、公平锁 十、非公平锁 十一、偏向锁 十二、对象锁 1三、线程锁 1四、锁粗化 1五、轻量级锁 1六、锁消除 1七、锁膨胀 1八、信号量
产生死锁的四个必要条件:
打破产生死锁的四个必要条件中的一个或几个,保证系统不会进入死锁状态。
活锁和死锁相似,不一样之处在于处于活锁的线程或进程的状态是不断改变的,活锁能够认为是一种特殊的饥饿。
一个现实的活锁例子是两我的在狭小的走廊碰到,两我的都试着避让对方好让彼此经过,可是由于避让的方向都同样致使最后谁都不能经过走廊。
简单的说就是,活锁和死锁的主要区别是前者进程的状态能够改变可是却不能继续执行。
饥饿是指系统不能保证某个进程的等待时间上界,从而使该进程长时间等待,当等待时间给进程推动和响应带来明显影响时,称发生了进程饥饿。当饥饿到必定程度的进程所赋予的任务即便完成也再也不具备实际意义时称该进程被饿死。
死锁是指在多道程序系统中,一组进程中的每个进程都无限期等待被该组进程中的另外一个进程所占有且永远不会释放的资源。
相同点:两者都是因为竞争资源而引发的。
不一样点:
悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操做。 乐观锁:假设不会发生并发冲突,只在提交操做时检查是否违反数据完整性。乐观锁不能解决脏读的问题。
对象锁是指Java为临界区synchronized(Object)语句指定的对象进行加锁,对象锁是独占排他锁。
对于对象锁,是针对一个对象的,它只在该对象的某个内存位置声明一个标志位标识该对象是否拥有锁,因此它只会锁住当前的对象。通常一个对象锁是对一个非静态成员变量进行syncronized修饰,或者对一个非静态方法进行syncronized修饰。对于对象锁,不一样对象访问同一个被syncronized修饰的方法的时候不会阻塞住。
在java.lang.Thread中有一个方法叫holdsLock(),它返回true若是当且仅当当前线程拥有某个具体对象的锁。
Java在过去很长一段时间只能经过synchronized关键字来实现互斥,它有一些缺点。好比你不能扩展锁以外的方法或者块边界,尝试获取锁时不能中途取消等。Java 5 经过Lock接口提供了更复杂的控制来解决这些问题。 ReentrantLock 类实现了 Lock,它拥有与 synchronized 相同的并发性和内存语义且它还具备可扩展性。
可重入锁,也叫作递归锁,指的是同一线程 外层函数得到锁以后 ,内层递归函数仍然有获取该锁的代码,但不受影响。
在Java环境下 ReentrantLock 和synchronized 都是可重入锁
CAS,全称为Compare and Swap,即比较-替换。假设有三个操做数:内存值V、旧的预期值A、要修改的值B,当且仅当预期值A和内存值V相同时,才会将内存值修改成B并返回true,不然什么都不作并返回false。固然CAS必定要volatile变量配合,这样才能保证每次拿到的变量是主内存中最新的那个值,不然旧的预期值A对某条线程来讲,永远是一个不会变的值A,只要某次CAS操做失败,永远都不可能成功
原文:Java架构笔记