【Thread】- ReentrantLock、ReentrantReadWriteLock

Java锁分类

  • 公平锁:线程获取锁的顺序是按照线程加锁的顺序分配,FIFO
  • 非公平锁:获取锁的抢占机制,是随机获取锁的,通常由OS统一调度

ReentrantLock:可重入互斥锁

ReentrantLock由最近成功获取该锁的线程全部,直到该线程释放该锁其余的线程才可获取多线程

可重入互斥锁解释:可重入的意思是当线程进入同步代码内部时,当在同步代码内部访问另外的同步方法,线程会自动获取另外同步方法的锁,换句话说当线程获取一个同步代码的锁时,能够自由访问其余的同步代码dom

可重入特性本质:线程执行同步代码时自动获取到共享对象的监视器,只要是目标对象监视器做用范围该线程均可彻底访问,线程执行完同步代码则释放监听器,其余线程获取监视器才能够访问,相似当司机拿着道路通行证能够自由使用通行证规定的路段,通行证类比对象的监视器,司机离开路段,将通行证转给另一个司机,同外一个司机也能够享受一样的服务(假设道路通行证不实名制)ide

特色:Lock锁对象可彻底取代synchronized功能,而且更加灵活测试


Lock的基础应用:this

测试类线程

public class LockDetail {
	
/**
    * 对象属性为Lock对象:static全部类实例共享
    * new ReentrantLock(false); 默认非公平锁/true表示公平锁
    */
private static Lock lock = new ReentrantLock();

public void show(String name) {
    
    try {
        lock.lock();
        for (int i = 0; i < name.length(); i++) {
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName() + ":" + name.charAt(i));
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        lock.unlock();
    }
}
}

测试代码日志

LockDetail lockDetail01 = new LockDetail();
LockDetail lockDetail02 = new LockDetail();

for(int i=0;i<10;i++){
    new Thread() {  
        public void run() {  
            lockDetail01.show("abcdefghijklmn");  
        };  
    }.start();  
    
    new Thread() {  
        public void run() {  
            lockDetail02.show("abcdefghijklmn");  
        };  
    }.start();  
}

效果code


读写锁:ReentrantReadWriteLock

特色:容许多个线程同时读,不容许同时写对象

读写锁测试类blog

class DefineLock {

// 建立读写锁:读锁能够同时读,一个读一个写,不能两个同时写
ReadWriteLock lock = new ReentrantReadWriteLock();

int data = 0;

public void write() {

    lock.writeLock().lock(); // 线程绑定写锁

    this.data = new Random().nextInt(5000);
    System.out.println(Thread.currentThread().getName() + ":准备写入数据");
    System.out.println(Thread.currentThread().getName() + ":写入数据:" + data);
    System.out.println(Thread.currentThread().getName() + ":写入完成");
    System.out.println("------------------------");

    lock.writeLock().unlock(); // 线程解除写锁
}

public void read() {

    lock.readLock().lock(); // 线程绑定读锁

    System.out.println(Thread.currentThread().getName() + ":准备读取数据");
    System.out.println(Thread.currentThread().getName() + ":读取数据:" + data);
    System.out.println(Thread.currentThread().getName() + ":准备读取数据");
    System.out.println("-------------------------");

    lock.readLock().unlock(); // 线程绑定读锁
}
}

读写锁测试代码

DefineLock lockTest = new DefineLock();

		for (int i = 0; i < 20; i++) {

			boolean flag = (new Random().nextInt()%2 == 0);
			
			new Thread(new Runnable() {
				public void run() {
                    if(flag){					
					     lockTest.write();
                    }else{
                    	lockTest.read();
                    }
				}
			}).start();
		}
	}

效果

分析 日志可看出每次写入的数据都是不一样的,不一样的读取线程读取到的数据多是相同的,必定程度能够说明多个线程读和一个线程写的读写锁的特性,固然能够将读取的过程用sleep分割开,若是看到读取线程交替就直接证实多线程读和单线程写的特性

可重入锁特性测试

测试类

public class Test {
	
Lock lock = new ReentrantLock();

public void show1(String str) throws InterruptedException{
    
    lock.lock();
    
    for(int i = 0; i < str.length(); i++){
        System.out.println(Thread.currentThread().getName()+":show1:" + str.charAt(i));
        Thread.sleep(100);
    }
    show2(str);
    lock.unlock();
}

public void show2(String str) throws InterruptedException{
    
    lock.lock();
    
    for(int i = 0; i < str.length(); i++){
        System.out.println(Thread.currentThread().getName()+":show2:" + str.charAt(i));
        Thread.sleep(500);
    }
    
    lock.unlock();
}

public static void main(String[] args) {

    Test test = new Test();
    String str = "abcdefge";
    
    for(int i = 0; i < 20; i++){
        new Thread(new Runnable() {
        
        @Override
        public void run() {
            try {
            test.show1(str);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
            
        }
    }).start();
    } 
}
}

效果:

剖析: 控制台输出能够看出每次都是单一线程执行完方法涉及到的同步代码后另一个线程才可访问,直接证实可重入的特性

相关文章
相关标签/搜索