赞
踩
一.序言:
类ReentrantLock具有完全互斥排他的效果,即同一时间只有一个线程在执行ReentrantLock.lock()方法后面的任务,这样做虽然保证了实例变量的线程安全性,单效率却是非常低的.所以在JDK中提供了一种读写锁ReentrantReadWriteLock类,使用它可以加快运行效率,在某些不需要操作实例变量的方法中,完全可以使用读写锁ReentrantReadLock来提升该方法的代码运行速度。
读写锁表示也有两个锁,一个是读操作相关的锁,也成为共享锁;另一个是写操作相关的锁,也叫排他锁。也就是多个读锁之间不互斥,读锁与写锁之间互斥,写锁与写锁互斥,在没有现成Thread进行写入操作时,进行读取操作的多个Thread都可以获取锁,而进行写入操作的Thread只有在获取写锁后才能进行写入操作,即多个Thread可以同时进行读取操作,但是同一时刻只允许一个Thread进行写入操作。
二.读读锁demo演示:
1.创建一个功能类,在类中调用ReentrantReadWriteLock读锁的方法
/** * Created by ${ligh} on 2019/7/9 上午8:48 */ public class Service { private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); public void read(){ try{ try{ lock.readLock().lock(); System.out.println("获得读锁 "+Thread.currentThread().getName()+" "+System.currentTimeMillis()); Thread.sleep(10000); }finally { lock.readLock().unlock(); } }catch (Exception e){ e.printStackTrace(); } } }
2.分别创建线程A和线程B进行读操作
线程A:
/** * Created by ${ligh} on 2019/7/9 上午8:53 */ public class ThreadA extends Thread{ private Service service; public ThreadA(Service service){ super(); this.service=service; } @Override public void run() { service.read(); } }
线程B:
/** * Created by ${ligh} on 2019/7/9 上午8:54 */ public class ThreadB extends Thread{ private Service service; public ThreadB(Service service){ super(); this.service=service; } @Override public void run() { service.read(); } }
3.测试读读锁:
/**
* Created by ${ligh} on 2019/7/9 上午8:48
*/
public class TestReadLock {
public static void main(String[] args) {
Service service = new Service();
ThreadA threadA = new ThreadA(service);
threadA.setName("A");
ThreadB threadB = new ThreadB(service);
threadB.setName("B");
threadA.start();
threadB.start();
}
}
4.测试结果:
总结:
通过打印结果来看,两个线程几乎同时进入lock()方法后面的代码,说明了lock.readLock()读锁可以提高程序运行效率,允许多个线程 同时执行lock()方法后面的代码。
三.写写锁demo演示:
1.创建一个功能类,调用ReentrantReadWriteLock写锁的方法
/** * Created by ${ligh} on 2019/7/9 上午9:13 */ public class Service { private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); public void write(){ try{ try{ lock.writeLock().lock(); System.err.println("获得写锁 "+Thread.currentThread().getName()+" "+System.currentTimeMillis()); Thread.sleep(1000); }finally { lock.writeLock().unlock(); } }catch (Exception e){ e.printStackTrace(); } } }
2.分别创建线程A,B调用写操作:
线程A:
/** * Created by ${ligh} on 2019/7/9 上午8:53 */ public class ThreadA extends Thread{ private Service service; public ThreadA(Service service){ super(); this.service=service; } @Override public void run() { service.write(); } }
线程B:
/** * Created by ${ligh} on 2019/7/9 上午8:54 */ public class ThreadB extends Thread{ private Service service; public ThreadB(Service service){ super(); this.service=service; } @Override public void run() { service.write(); } }
3.创建测试类:
/** * Created by ${ligh} on 2019/7/9 上午9:18 */ public class TestWriteLock { public static void main(String[] args) { Service service = new Service(); ThreadA threadA = new ThreadA(service); threadA.setName("A"); ThreadB threadB = new ThreadB(service); threadB.setName("B"); threadA.start(); threadB.start(); } }
4.测试结果:
总结:
通过打印结果显示: 使用写锁代码lock.writeLock()的效果就是同一时间只允许一个线程执行lock()后面的代码,也就是互斥了。
四.读写锁demo演示:
1.创建一个功能类,调用ReentrantReadWriteLock读锁和写锁的方法
/** * Created by ${ligh} on 2019/7/9 上午9:25 */ public class Service { private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); /** * 读锁 */ public void read(){ try{ try{ lock.readLock().lock(); System.err.println("获得读锁 "+Thread.currentThread().getName()+" "+System.currentTimeMillis()); Thread.sleep(10000); }finally { lock.readLock().unlock(); } }catch (Exception e){ e.printStackTrace(); } } /** * 写锁 */ public void write(){ try{ try{ lock.writeLock().lock(); System.err.println("获得写锁 "+Thread.currentThread().getName()+" "+System.currentTimeMillis()); Thread.sleep(10000); }finally { lock.writeLock().unlock(); } }catch (Exception e){ e.printStackTrace(); } } }
2.创建线程A调用读锁,线程B调用写锁
线程A:
/** * Created by ${ligh} on 2019/7/9 上午9:30 * * 线程A调用读锁 */ public class ThreadA extends Thread{ private Service service; public ThreadA(Service service){ super(); this.service=service; } @Override public void run() { service.read(); } }
线程B:
/** * Created by ${ligh} on 2019/7/9 上午9:32 */ public class ThreadB extends Thread{ private Service service; public ThreadB(Service service){ super(); this.service = service; } @Override public void run() { service.write(); } }
3.创建测试类:
/**
* Created by ${ligh} on 2019/7/9 上午9:33
*/
public class TestReadWriteLock {
public static void main(String[] args) {
Service service = new Service();
ThreadA threadA = new ThreadA(service);
threadA.setName("A");
ThreadB threadB = new ThreadB(service);
threadB.setName("B");
threadA.start();
threadB.start();
}
}
4.测试结果:
4.总结:
1).通过打印结果显示: “读写"操作是互斥的,而且下一个示例说明"写读"操作也是互斥的,即只要出现"写操作"的过程,就是互斥的,
2).通过测试"读写”,"写读"和"写写"都是互斥的;而"读读"是异步的,非互斥的
3).通过测试可以使用Lock对象将synchronized关键字替换掉,而且其具有的独特功能也是synchronized所不具有的,在学习并发时,Lock是synchronized关键字的进阶,掌握Lock有助于学习并发包中源代码的实现原理,在并发包中大量的类使用了Lock接口作为同步的处理方式。
个人心得:
最近一直在研究多线程,并且发现里面的东西实际没有那么难,尤其是研究实现原理之后,看JDK的源码就轻松了很多。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。