从广义来讲,Java平台提供的线程同步机制包括锁、volatile关键字、final关键字、static关键字以及一些相关的API。本文主要介绍Java平台中用于协调线程间共享数据访问的相关关键字和API,固然也是经常使用的线程同步方法。java
学习线程都知道,在多个线程并发访问共享变量、共享资源时,会形成线程安全问题,那怎么解决呢?编程
咱们很容易想到一种保障线程安全的方法--将多个线程对于并发访问转换为串行访问,即一个共享数据一次只能被一个线程访问,该线程访问结束后其余线程才能对其进行访问。锁(Lock)就是利用这种思路以保障线程安全的线程同步机制。api
一些名词概念:缓存
这些复杂概念就不深研究了,只简单了解,想深刻研究的小伙伴自行查阅相关书籍。安全
Java平台中的任何一个对象都有惟一一个与之关联的锁,这种锁称为监视器(Monitor)或者内部锁(Intrinsic Lock)。内部锁可以保障原子性、可见性和有序性。内部锁时经过synchronized 关键字实现的。synchronized提供了一种独占的加锁方式,是比较经常使用的线程同步的关键字,通常在“线程安全的单例”中广泛使用。该关键字可以保证代码块的同步性和方法层面的同步。多线程
synchronized 关键字修饰的代码块就被称为同步块。并发
//使用synchronized关键字实现线程安全的单例模式
private static Singleton instance;
public static Singleton getInstance(){
if(instance == null){
synchronized (Singleton.class)
{
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
privateSingleton(){ }
复制代码
synchronized 关键字修饰的方法就被称为同步方法。 同步方法的这个方法体就是一个临界区。负载均衡
public static synchronized Singleton getInstance2(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
private Singleton(){ }
复制代码
以读写锁为例,Lock的使用方式很简单,只须要在须要加锁的地方先获取锁,操做完成以后释放锁,须要注意的是:学习
要在finally中释放锁,这样作的目的是保证在获取到所以后,最终都是可以被释放; 不要讲获取锁的过程写在try代码块中,防止在获取锁发生异常时致使的锁无端释放。spa
Lock lock = new ReentrantLock();
lock.lock();
try{
//可能会出现线程安全的操做
}finally{
//必定在finally中释放锁
//也不能把获取锁在try中进行,由于有可能在获取锁的时候抛出异常
lock.ublock();
}
复制代码
Lock api Lock是一个接口,定义了锁的获取和释放等基本操做。
void lock()
线程调用该方法获取锁,获取锁后返回;
void lockInterruptibly() throws InterruptedException
可中断地获取锁,和lock()方法的区别在于该方法能够响应中断;
boolean tryLock()
尝试非阻塞获取锁,线程调用该方法后马上返回,成功获取到锁返回true,不然返回false;
boolean tryLock(long time, TimeUnit unit) throws InterruptedException
超时获取锁,该方法在如下3中状况会返回: 在超时时间内得到锁; 在超时时间被中断; 超时时间结束仍未得到,返回false。
void unlock()
释放锁;
Condition newCondition()
获取等待通知Condition组件,该组件和当前锁绑定,只有线程获取到了锁才能调用await()方法,调用后,当前线程释放锁。
在总结二者的区别和联系以前先引入两个概念:隐式锁和显式锁。 上面都有涉及,下面仔细讲解一下。
隐式锁: 隐式获取锁,synchronized是它的表明,使用者不须要关心其内部锁的获取和释放,全部的锁的相关操做都由具体的关键字完成; 显式锁: 显示地获取锁,Lock是它的表明,须要使用者在使用的时候显示地获取和释放锁。
显式锁和隐式锁都实现了对临界区访问的控制,可是显式锁提供了更灵活、更强大的接口:
就Lock接口提供的synchronized关键字不具有的特性作一个分析描述:
特性 | 描述 |
---|---|
尝试非阻塞获取锁 | 当前线程尝试获取锁,若是锁未被其余线程获取,当前线程成功获取并持有锁 |
可中断获取锁 | 获取锁的线程可以响应中断,当获取到锁的线程被中断时,抛出中断异常,锁被释放 |
超时获取锁 | 在指定的时间内获取锁,若是在指定的时间内未获取到,获取锁失败,返回 |
volatile “不稳定”的意思。volatile关键字用于修饰共享可变变量,既没有使用 final 关键字修饰的实例变量或静态变量,相应的变量就被称做 volatile变量。 private volatile int logLevel;
volatile 关键字表示被修饰的变量的值容易发生变化(即被其余线程更改),于是不稳定。volatile变量的不稳定性意味着对这种变量的读和写都必须从高速缓存或者主内存中读取,以读取变量的相对新值。
volatile 关键字常被称为轻量级锁,其做用与锁的做用有相同的地方:保证可见性和有序性。所不一样的是,在原子性方面它仅能保障写volatile 变量操做的原子性,但没有锁 的排他性;其次,volatile 关键字的使用不会引发上下文切换(这是volatile 被称为轻量级的缘由)。
对于多线程编程来讲,此文介绍的仅是九牛一毛,在解决负载均衡问题,充分利用CPU资源方面,多线程编程起着相当重要的做用。 我才刚刚入门,加油,菜鸡!!