1、公平锁:多个线程之间可以按照线程申请锁的顺序获取锁;
2、非公平锁:多个线程之间获取锁的顺序不一定按照申请锁的顺序获得;Synchronized、ReentrantLock默认是非公平锁,后者可以通过构造参数获取公平锁。
3、可重入锁又叫递归锁:是指在一个同步方法内部调用另外一个同步方法时,获得的锁是同一把锁,避免死锁;举例如下:
public class TestLock {
public synchronized void hello() {
System.out.println(Thread.currentThread().getName() + "\t 测试递归锁");
//实现的效果就是hello()方法和world()方法总是总一个线程、具有原子性
world();
}
public synchronized void world() {
System.out.println(Thread.currentThread().getName() + "\t 测试递归锁2");
}
public static void main(String[] args) {
TestLock tl = new TestLock();
for (int i = 0; i < 10; i++) {
new Thread(() -> {
tl.hello();
}, String.valueOf(i)).start();
}
}
}
打印结果:
0 测试递归锁
0 测试递归锁2
6 测试递归锁
6 测试递归锁2
4 测试递归锁
4 测试递归锁2
5 测试递归锁
5 测试递归锁2
3 测试递归锁
3 测试递归锁2
2 测试递归锁
2 测试递归锁2
1 测试递归锁
1 测试递归锁2
9 测试递归锁
9 测试递归锁2
8 测试递归锁
8 测试递归锁2
7 测试递归锁
7 测试递归锁2
hello方法和world方法总是一起执行
4、自旋锁:是指获取锁的线程不会立即阻塞,而是利用循环比较的方式去获取锁,好处就是减少上下文切换,缺点是循环比较会消耗cpu的性能,举例如下:
public class TestLock2 {
//利用在这个原子类中存入当前线程,为获取锁,否则自循环等待其他线程释放锁以获得锁
AtomicReference<Thread> atomicReference = new AtomicReference<>();
public void lock() {
Thread thread = Thread.currentThread();
//比较替换成功取反为false跳出循环
while (!atomicReference.compareAndSet(null, thread)) {
}
System.out.println(thread.getName() + "\t come in");
}
public void unlock() {
Thread thread = Thread.currentThread();
//释放锁就是将值为当线程的内存值更新为null,好让下一个线程获取锁
atomicReference.compareAndSet(thread, null);
System.out.println(thread.getName() + "\t come out");
}
public static void main(String[] args) {
TestLock2 tl = new TestLock2();
for (int i = 0; i < 10; i++) {
new Thread(() -> {
tl.lock();
try {
//模拟每个线程进来需要消耗1秒钟
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
tl.unlock();
}
}, String.valueOf(i)).start();
}
}
}
打印结果:
0 come in
0 come out
6 come in
6 come out
4 come in
4 come out
2 come in
2 come out
9 come in
9 come out
8 come in
8 come out
7 come in
7 come out
1 come in
1 come out
5 come in
5 come out
3 come in
3 come out
取得了获取锁,释放锁的效果
5、独占锁:一次只能被一个线程拥有;共享锁:一次可以被多个线程共有;其中读读是共享,写读、读写、写写都互斥
举例如下:
public class TestLock3 {
Map<String, Object> params = new HashMap<>();
ReentrantReadWriteLock rw = new ReentrantReadWriteLock();
/**
* 读共享
*
* @param k
* @return
*/
public Object get(String k) {
rw.readLock().lock();
Object value = null;
try {
value = params.get(k);
System.out.println(Thread.currentThread().getName() + "\t 读到的值" + value);
} catch (Exception e) {
e.printStackTrace();
} finally {
rw.readLock().unlock();
}
return value;
}
/**
* 写互斥
*
* @param key
* @param value
* @return
*/
public boolean setParams(String key, Object value) {
rw.writeLock().lock();
if (value == null) {
return false;
}
try {
params.put(key, value);
System.out.println(Thread.currentThread().getName() + "\t key=" + key);
} catch (Exception e) {
e.printStackTrace();
} finally {
rw.writeLock().unlock();
}
return true;
}
public static void main(String[] args) {
TestLock3 testLock3 = new TestLock3();
//多线程写
for (int i = 0; i < 10; i++) {
final int a = i;
new Thread(() -> {
testLock3.setParams(String.valueOf(a), UUID.randomUUID().toString().substring(0, 3));
}, String.valueOf(i)).start();
}
//先让写线程进行
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//多线程读
for (int i = 0; i < 10; i++) {
final int b = i;
new Thread(() -> {
testLock3.get(String.valueOf(b));
}, String.valueOf(i)).start();
}
}
}