1.可重入锁:
1)概念:锁具备可重入性,则称为可重入锁;可重入性表明了锁的分配机制,是基于线程分配的,而不是基于方法调用分配的;
2):synchronized 和 ReentrantLock都是属于可重入锁
3):举例说明
class ReentrantLockClass{
//当某个线程A申请到methodOne()方法的锁,执行methodOne()方法,这时该对象被锁住
//在methodOne()方法中调用了methodTwo()方法,methodTwo()也是需要申请锁资源的
//此时如果线程A仍然需要申请锁资源才能执行methodTwo()方法,则线程A则会无线等待下去
//因为这个对象的所资源已被线程A申请methodOne()方法的锁锁住
//但是我们在实际情况下是不会发生这种情况的,所以synchronized是可重入锁
public synchronized void methodOne(){
//处理业务
methodTwo();
//处理业务
}
public synchronized void methodTwo(){
//处理业务
}
}
2.公平锁和非公平锁
1).公平锁:尽可能的按照申请锁资源的顺序执行,当同时有多个线程等待一个锁时,这个锁被释放掉,则等待锁资源时间最长的线程,获得该锁权限
2).非公平锁:无法保证线程的执行顺序是按照申请锁资源的顺序执行的,可能导致某个或者一些线程永远获取不到锁
3).synchronized 是非公平锁
ReentrantLock 默认是非公平锁,即通过无参构造函数创建的 ,可以通过有参的构造函数创建公平锁
ReentrantReadWriteLock 默认是非公平锁,即通过无参构造函数创建的 ,可以通过有参的构造函数创建公平锁
3.读写锁ReentrantReadWriteLock
1) 通过synchronized实现读锁
package com.roger.juc;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ReadWriterLockMain {
public synchronized void readFile() throws Exception{
long startTime = System.currentTimeMillis();
System.out.println("开始执行时间-startTime = " + startTime);
for(int i=0; i < 5; i++){
Thread.sleep(20);
System.out.println(Thread.currentThread().getName() + "正在读取文件信息....");
}
System.out.println(Thread.currentThread().getName() + "读取完毕");
long endTime = System.currentTimeMillis();
System.out.println("结束时间-endTime = " + endTime);
}
public static void main(String[] args) {
final ReadWriterLockMain readWriterLockMain = new ReadWriterLockMain();
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
try {
readWriterLockMain.readFile();
} catch (Exception e) {
}
}
});
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
try {
readWriterLockMain.readFile();
} catch (Exception e) {
}
}
});
thread1.start();
thread2.start();
}
}
执行结果:
开始执行时间-startTime = 1542781854228 Thread-0正在读取文件信息.... Thread-0正在读取文件信息.... Thread-0正在读取文件信息.... Thread-0正在读取文件信息.... Thread-0正在读取文件信息.... Thread-0读取完毕 结束时间-endTime = 1542781854330 开始执行时间-startTime = 1542781854330 Thread-1正在读取文件信息.... Thread-1正在读取文件信息.... Thread-1正在读取文件信息.... Thread-1正在读取文件信息.... Thread-1正在读取文件信息.... Thread-1读取完毕 结束时间-endTime = 1542781854432 |
结论:通过synchronized实现读锁,是互斥的,只有线程Thread-0执行完成后,Thread-1线程才能执行
2)通过ReentrantReadWriteLock实现读锁
package com.roger.juc;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ReadWriterLockMain {
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
public void readFile(){
//添加读锁
lock.readLock().lock();
try {
long startTime = System.currentTimeMillis();
System.out.println("开始执行时间-startTime = " + startTime);
for(int i=0; i < 5; i++){
Thread.sleep(20);
System.out.println(Thread.currentThread().getName() + "正在读取文件信息....");
}
System.out.println(Thread.currentThread().getName() + "读取完毕");
long endTime = System.currentTimeMillis();
System.out.println("结束时间-endTime = " + endTime);
}catch (Exception e){
}finally {
//释放读锁
lock.readLock().unlock();
}
}
public static void main(String[] args) {
final ReadWriterLockMain readWriterLockMain = new ReadWriterLockMain();
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
try {
readWriterLockMain.readFile();
} catch (Exception e) {
}
}
});
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
try {
readWriterLockMain.readFile();
} catch (Exception e) {
}
}
});
thread1.start();
thread2.start();
}
}
执行结果:
开始执行时间-startTime = 1542782940771 开始执行时间-startTime = 1542782940772 Thread-0正在读取文件信息.... Thread-1正在读取文件信息.... Thread-0正在读取文件信息.... Thread-1正在读取文件信息.... Thread-0正在读取文件信息.... Thread-1正在读取文件信息.... Thread-0正在读取文件信息.... Thread-1正在读取文件信息.... Thread-0正在读取文件信息.... Thread-0读取完毕 结束时间-endTime = 1542782940871 Thread-1正在读取文件信息.... Thread-1读取完毕 结束时间-endTime = 1542782940872 |
结论:ReentrantReadWriteLock的读锁是可以共享的,执行效率明显高于synchronized
3)ReentrantReadWriteLock的读锁和写锁
package com.roger.juc;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ReadWriterLockMain {
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
public void readFile(){
//添加读锁
lock.readLock().lock();
boolean readLock = lock.isWriteLocked();
if(!readLock){
System.out.println("当前为读锁");
}
try {
long startTime = System.currentTimeMillis();
System.out.println("开始执行时间-startTime = " + startTime);
for(int i=0; i < 5; i++){
Thread.sleep(20);
System.out.println(Thread.currentThread().getName() + "正在读取文件信息....");
}
System.out.println(Thread.currentThread().getName() + "读取完毕");
long endTime = System.currentTimeMillis();
System.out.println("结束时间-endTime = " + endTime);
}catch (Exception e){
}finally {
System.out.println("释放读锁");
lock.readLock().unlock();
}
}
public void writeFile(){
//添加写锁
lock.writeLock().lock();
boolean writeLock = lock.isWriteLocked();
if(writeLock){
System.out.println("当前为写锁");
}
try {
long startTime = System.currentTimeMillis();
System.out.println("开始执行时间-startTime = " + startTime);
for(int i=0; i < 5; i++){
Thread.sleep(20);
System.out.println(Thread.currentThread().getName() + "正在写文件信息....");
}
System.out.println(Thread.currentThread().getName() + "写完毕");
long endTime = System.currentTimeMillis();
System.out.println("结束时间-endTime = " + endTime);
}catch (Exception e){
}finally {
System.out.println("释放写锁");
lock.writeLock().unlock();
}
}
public static void main(String[] args) {
final ReadWriterLockMain readWriterLockMain = new ReadWriterLockMain();
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.execute(new Runnable() {
@Override
public void run() {
readWriterLockMain.readFile();
}
});
executorService.execute(new Runnable() {
@Override
public void run() {
readWriterLockMain.writeFile();
}
});
}
}
执行结果:
当前为读锁 开始执行时间-startTime = 1542783555994 pool-1-thread-1正在读取文件信息.... pool-1-thread-1正在读取文件信息.... pool-1-thread-1正在读取文件信息.... pool-1-thread-1正在读取文件信息.... pool-1-thread-1正在读取文件信息.... pool-1-thread-1读取完毕 结束时间-endTime = 1542783556096 释放读锁 当前为写锁 开始执行时间-startTime = 1542783556096 pool-1-thread-2正在写文件信息.... pool-1-thread-2正在写文件信息.... pool-1-thread-2正在写文件信息.... pool-1-thread-2正在写文件信息.... pool-1-thread-2正在写文件信息.... pool-1-thread-2写完毕 结束时间-endTime = 1542783556198 释放写锁 |
结论:ReentrantReadWriteLock的读锁和写锁时互斥,
也就说如果一个线程已经占用了对象的读锁,那么其他线程想获取到这个对象的写锁,则需要等待
占用读锁的线程释放读锁之后,才能执行写操作;
当一个线程已经占用了对象的写锁,那么其他线程想获取到这个对象的读锁或者写锁,则需要等待
占用写锁的线程释放写锁之后,才能执行相应的操作