1、synchronized:它是java中的一个关键字,它可以把任意一个非NULL的对象当作锁。
1)作用于方法时,锁住的是对象的实例(this);
2)当作用于静态方法时,锁住的是Class实例,又因为Class的相关数据存储在永久带PermGen(jdk1.8则是metaspace),永久带是全局共享的,因此静态方法锁相当于类的一个全局锁,会锁所有调用该方法的线程;
3)synchronized作用于一个对象实例时,锁住的是所有以该对象为锁的代码块。
2、Lock:Lock有一个实现类:ReentrantLock,它实现了Lock里面的方法,但是使用Lock的时候必须注意它不会像synchronized执行完成之后或者抛出异常之后自动释放锁,而是需要你主动释放锁,所以我们必须在使用Lock的时候加上try{}catch{}finally{}块,并且在finally中释放占用的锁资源。
Lock和synchronized最大的区别就是当使用synchronized,一个线程抢占到锁资源,其他线程必须等待;而使用Lock,一个线程抢占到锁资源,其他的线程可以不等待或者设置等待时间,实在抢不到可以去做其他的业务逻辑。
3、ReadWriteLock(读读共享,其他全互斥):它可以实现读写锁,当读取的时候线程会获得read锁,其他线程也可以获得read锁同时并发的去读取,但是写程序运行获取到write锁的时候,其他线程是不能进行操作的,因为write是排它锁,而上面介绍的两种不管你是read还是write没有抢到锁的线程都会被阻塞或者中断,它也是个接口,里面定义了两种方法readLock()和readLock(),他的一个实现类是ReentrantReadWriteLock。
关于读写锁的一个缓存例子CacheDemo:
package resource.java.ordinary.mul.thread;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* 一个缓存demo,读写锁例子,实现读和写互斥、写和写互斥,但有可以多个并发的读,可提高系统性能
*
* @author xiao
*/
public class CacheDemo {
// 数据
private Map<String, Object> cache = new HashMap<>();
// 读写锁
private ReadWriteLock rwl = new ReentrantReadWriteLock();
public Object getData(String key) {
// 上读锁,多个读时可以并发,不会造成对数据的破坏
rwl.readLock().lock();
Object value = null;
try {
value = cache.get(key);
// 如果数据为空
if (value == null) {
// 释放读锁上写锁,上写锁后,数据不能被读
rwl.readLock().unlock();
rwl.writeLock().lock();
try {
// 此处判断是为防止多个线程同时进入到这里时,多个线程对数据进行重复写
if (value == null) {
// 如果没有数据,则去查DB获取数据
value = "XXX";
}
} finally {
// 读取数据后释放写锁
rwl.writeLock().unlock();
}
// 获取完数据后,恢复读锁,重新读取数据
rwl.readLock().lock();
}
} finally {
// 重新读取数据释放读锁
value = cache.get(key);
rwl.readLock().unlock();
}
return value;
}
}