java基础——多线程(锁lock&&条件阻塞Condition)
来源:互联网 发布:张翔起诉淘宝网 编辑:程序博客网 时间:2024/06/04 18:02
一、Lock实现线程同步通信
1、Lock比传统线程模型中的synchronized方式更加面向对象,与生活中的锁类似,锁本身也应该是一个对象。两个线程执行的代码片段要实现同步互斥的效果,它们必须用同一个Lock对象。
- class Output{
- //1、实例化一把锁,但Lock是个接口,要用ReentrantLock作为实现类
- Lock lock = new ReentrantLock();
- public void output1(String a){
- int len = a.length();
- lock.lock();//2、把所要锁起来的程序加锁
- try {
- for (int i = 0; i < len; i++) {
- System.out.print(a.charAt(i));//打印每个字母
- }
- } finally {
- lock.unlock(); //3、在finally里面打开锁
- }
- System.out.println();
- }
2、读写锁:分为读锁和写锁,多个读锁不互斥,读锁与写锁互斥,这是由jvm自己控制的,你只要上好相应的锁即可。如果你的代码只读数据,可以很多人同时读,但不能同时写,那就上读锁;如果你的代码修改数据,只能有一个人在写,且不能同时读取,那就上写锁。总之,读的时候上读锁,写的时候上写锁!
1)下面是jdk配的Demo
- class CachedData {
- Object data;
- volatile boolean cacheValid;
- final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();//读写锁实例
- void processCachedData() {
- rwl.readLock().lock(); //1、一开始假设有数据,上读锁
- if (!cacheValid) {//判断是否有数据,有跳2、;没有跳4、
- // Must release read lock before acquiring write lock
- rwl.readLock().unlock(); //4、解读锁上写锁
- rwl.writeLock().lock();
- try {
- // Recheck state because another thread might have
- // acquired write lock and changed state before we did.
- if (!cacheValid) {
- data = ... //5、写数据
- cacheValid = true;
- }
- // Downgrade by acquiring read lock before releasing write lock
- rwl.readLock().lock(); //6、上读锁,解写锁
- } finally {
- rwl.writeLock().unlock(); // Unlock write, still hold read
- }
- }
- try {
- use(data);// 2、有数据,直接读
- } finally {
- rwl.readLock().unlock();//3、读完,解锁
- }
- }
- }
- public class CacheDemo {
- <span style="white-space:pre"> </span>/**
- <span style="white-space:pre"> </span> * 需求(面试题): 缓存系统(那一个数据,如果缓存有,直接在缓存取数据; 如果没有,缓存就去找数据库,等你下次再找的时候我就可以直接给你)
- <span style="white-space:pre"> </span> */
- <span style="white-space:pre"> </span>// 1、创建一个Map,用于保存数据键值对
- <span style="white-space:pre"> </span>private Map<String, Object> cache = new HashMap<String, Object>();
- <span style="white-space:pre"> </span>public static void main(String[] args) {
- <span style="white-space:pre"> </span>}
- <span style="white-space:pre"> </span>// 定义一把读写锁
- <span style="white-space:pre"> </span>private ReadWriteLock rw1 = new ReentrantReadWriteLock();
- <span style="white-space:pre"> </span>public Object getData(String key) {
- <span style="white-space:pre"> </span>rw1.readLock().lock();
- <span style="white-space:pre"> </span>// 根据key得到一个Object
- <span style="white-space:pre"> </span>Object value = null;
- <span style="white-space:pre"> </span>try {
- <span style="white-space:pre"> </span>value = cache.get(key);
- <span style="white-space:pre"> </span>if (value == null) {
- <span style="white-space:pre"> </span>rw1.readLock().unlock();
- <span style="white-space:pre"> </span>rw1.writeLock().lock();
- <span style="white-space:pre"> </span>try {
- <span style="white-space:pre"> </span>if(value == null){ //注意要再次判断value的值,防止多个线程进来了,多次设值
- <span style="white-space:pre"> </span>value = "bbbbb";
- <span style="white-space:pre"> </span>}
- <span style="white-space:pre"> </span>} finally {
- <span style="white-space:pre"> </span>rw1.writeLock().unlock();
- <span style="white-space:pre"> </span>}
- <span style="white-space:pre"> </span>rw1.readLock().lock();
- <span style="white-space:pre"> </span>}
- <span style="white-space:pre"> </span>} finally {
- <span style="white-space:pre"> </span>rw1.readLock().unlock();
- <span style="white-space:pre"> </span>}
- <span style="white-space:pre"> </span>return value;
- <span style="white-space:pre"> </span>}
- }
二、条件阻塞Condition的应用
1、在等待 Condition 时,允许发生“虚假唤醒”,这通常作为对基础平台语义的让步。对于大多数应用程序,这带来的实际影响很小,因为 Condition 应该总是在一个循环中被等待,并测试正被等待的状态声明。某个实现可以随意移除可能的虚假唤醒,但建议应用程序程序员总是假定这些虚假唤醒可能发生,因此总是在一个循环中等待。
2、一个锁内部可以有多个Condition,即有多路等待和通知,可以参看jdk1.5提供的Lock与Condition实现的可阻塞队列的应用案例,从中除了要体味算法,还要体味面向对象的封装。在传统的线程机制中一个监视器对象上只能有一路等待和通知,要想实现多路等待和通知,必须嵌套使用多个同步监视器对象。(如果只用一个Condition,两个放的都在等,一旦一个放的进去了,那么它通知可能会导致另一个放接着往下走。)
- import java.util.concurrent.locks.Condition;
- import java.util.concurrent.locks.Lock;
- import java.util.concurrent.locks.ReentrantLock;
- public class ConditionCommunication {
- /**
- * 需求:定义三个线程,一个主线程,两个子线程。主线程循环2次,接着子线程1循环3次,接着子线程2循环4次,接着又回到主线程循环2次,如此循环5次。
- */
- public static void main(String[] args) {
- final Business bus = new Business();
- new Thread(new Runnable() {
- @Override
- public void run() {
- for (int i = 1; i <= 4; i++) {
- bus.sub1(i);
- }
- }
- }).start();
- new Thread(new Runnable() {
- @Override
- public void run() {
- for (int i = 1; i <= 4; i++) {
- bus.sub2(i);
- }
- }
- }).start();
- for (int i = 1; i <= 4; i++) {
- bus.main(i);
- }
- }
- static class Business {
- private int isExcu = 1; //初始值为1,默认先让主线程执行
- Lock lock = new ReentrantLock();
- //定义三个Condition便于区分唤醒三个线程
- Condition conditionMain = lock.newCondition();
- Condition conditionSub1 = lock.newCondition();
- Condition conditionSub2 = lock.newCondition();
- public void sub1(int i) {
- lock.lock();
- try {
- while (isExcu !=2) { //执行值不为2,等待
- try {
- conditionSub1.await();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- for (int j = 1; j <= 2; j++) {
- System.out.println(" 子线程sub1 "
- + Thread.currentThread().getName() + " 正在输出 "
- + j + " in loop of " + i);
- isExcu = 3; //执行完sub1,赋值给isExcu,让sub2执行
- conditionSub2.signal();//唤醒sub2
- }
- } finally {
- lock.unlock();
- }
- }
- public void sub2(int i) {
- lock.lock();
- try {
- while (isExcu!=3) {//执行值不为3,本身就等待
- try {
- conditionSub2.await();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- for (int j = 1; j <= 3; j++) {
- System.out.println(" 子线程sub2 "
- + Thread.currentThread().getName() + " 正在输出 "
- + j + " in loop of " + i);
- isExcu = 1;//执行完sub2,赋值给isExcu,让main执行
- conditionMain.signal();//唤醒main
- }
- } finally {
- lock.unlock();
- }
- }
- public synchronized void main(int i) {
- lock.lock();
- try {
- while (isExcu!= 1) {//执行值不为1,本身就等待
- try {
- conditionMain.await();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- for (int k = 1; k <= 1; k++) {
- System.out.println(" 主线程 "
- + Thread.currentThread().getName() + " 正在输出 "
- + k + " in loop of " + i);
- isExcu = 2;//执行完main,赋值给isExcu,让sub1执行
- conditionSub1.signal();//唤醒sub1
- }
- } finally {
- lock.unlock();
- }
- }
- }
- }
打印结果:
主线程 main 正在输出 1 in loop of 1
子线程sub1 Thread-0 正在输出 1 in loop of 1
子线程sub1 Thread-0 正在输出 2 in loop of 1
子线程sub2 Thread-1 正在输出 1 in loop of 1
子线程sub2 Thread-1 正在输出 2 in loop of 1
子线程sub2 Thread-1 正在输出 3 in loop of 1
主线程 main 正在输出 1 in loop of 2
子线程sub1 Thread-0 正在输出 1 in loop of 2
子线程sub1 Thread-0 正在输出 2 in loop of 2
子线程sub2 Thread-1 正在输出 1 in loop of 2
子线程sub2 Thread-1 正在输出 2 in loop of 2
子线程sub2 Thread-1 正在输出 3 in loop of 2
主线程 main 正在输出 1 in loop of 3
子线程sub1 Thread-0 正在输出 1 in loop of 3
子线程sub1 Thread-0 正在输出 2 in loop of 3
子线程sub2 Thread-1 正在输出 1 in loop of 3
子线程sub2 Thread-1 正在输出 2 in loop of 3
子线程sub2 Thread-1 正在输出 3 in loop of 3
主线程 main 正在输出 1 in loop of 4
子线程sub1 Thread-0 正在输出 1 in loop of 4
子线程sub1 Thread-0 正在输出 2 in loop of 4
子线程sub2 Thread-1 正在输出 1 in loop of 4
子线程sub2 Thread-1 正在输出 2 in loop of 4
子线程sub2 Thread-1 正在输出 3 in loop of 4
- java基础——多线程(锁lock&&条件阻塞Condition)
- java基础——多线程(锁lock&&条件阻塞Condition)
- Java多线程——Condition条件
- Java并发之读写锁Lock和条件阻塞Condition的应用
- Java并发之读写锁Lock和条件阻塞Condition的应用
- Java并发之读写锁Lock和条件阻塞Condition的应用
- 《深入浅出 Java Concurrency》—锁机制(四) 锁释放与条件变量 (Lock.unlock And Condition)
- 《深入浅出 Java Concurrency》—锁机制(四) 锁释放与条件变量 (Lock.unlock And Condition)
- JAVA多线程—Lock&Condition实现线程同步通信
- java多线程--condition条件
- java基础巩固---(线程)锁机制:synchronized、Lock、Condition
- java实现缓冲区(阻塞队列,condition,lock)
- java多线程学习笔记(七) ——消费者与生产者(LOCK、Condition接口)
- Java多线程4- Lock、Condition
- Java多线程4- Lock、Condition
- Java多线程与并发应用-(9)-锁lock+条件阻塞conditon实现线程同步通信
- 多线程——用Lock(锁)和Condition(监听器)来优化生产者消费者模式
- Java多线程系列--Condition条件
- AP同频干扰
- 【教程】 如何在linux/mac下安装pascal
- ORCLE-Select 语句执行顺序以及如何提高Oracle 基本查询效率
- 前台页面优化全攻略(一)
- java专题——插入排序
- java基础——多线程(锁lock&&条件阻塞Condition)
- spring MVC定时删除项目下的指定文件夹下的文件
- java专题——单向链表(逆序)
- 自定义标签入门
- Codeforces Round #263(div2)C. Appleman and Toastman
- 《Linux C编程一站式学习》读书笔记(1)
- 使用clutch对App进行砸壳
- 找到一个专门学习devExpress的网站
- hdoj 1421 搬寝室 【dp】