线程高级应用-心得5-java5线程并发库中Lock和Condition实现线程同步通讯
1.Lock相关知识介绍
好比我同时种了几块地的麦子,然后就等待收割。收割时,则是哪块先熟了,先收割哪块。
下面举一个面试题的例子来引出Lock缓存读写锁的案例,一个load()和get()方法返回值为空时的情况;load()的返回值是一个代理对象,而get()却是一个实实在在的对象;所以当返回对象为空是,get()返回null,load()返回一个异常对象;具体分析如下:
一个读写锁的缓存库案例;用上面那道面试题分析则很好理解:
线程阻塞问题:运用多个Condition对象解决
2. Lock接口锁的使用
Lock与synchronized最大区别就是:前者更面向对象;Lock要求程序员手动释放锁,synchronized自动释放
package com.java5.thread.newSkill; //concurrent就是java5新增的线程并发库包
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; /**
* Lock接口锁的使用
* Lock与synchronized最大区别就是:前者更面向对象;
* Lock要求程序员手动释放锁,synchronized自动释放。
*/
public class LockTest { public static void main(String[] args) {
new LockTest().init(); } // 该方法的作用是:外部类的静态方法不能实例化内部类对象;所以不能直接在外部类的main实例化,要创建一个中介的普通方法
private void init() {
final Outputer outputer = new Outputer();
// 线程1
new Thread(new Runnable() { @Override
public void run() {
while (true) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
outputer.output("yangkai");
}
}
}).start();
// 线程2
new Thread(new Runnable() { @Override
public void run() {
while (true) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
outputer.output("123456");
}
}
}).start();
} static class Outputer {
Lock lock = new ReentrantLock(); public void output(String name) {
//上锁
lock.lock();
try {
for (int i = 0; i < name.length(); i++) {
// 读取字符串内一个一个的字符
System.out.print(name.charAt(i));
}
System.out.println();
} finally {
//释放锁;
/*这里放到finally里的原因是:万一上锁的这个方法中有异常发生;
* 那就不执行释放锁代码了,也就是成死锁了;好比你上厕所晕里面了;
* 后面的人等啊等的永远进不去似的
*/
lock.unlock();
}
} } /*
* 如果不使用线程锁Lock会出现以下情况: yangkai 123456 yangkai 1y2a3n4g5k6 ai
*/
}
3、读写锁的案例
package com.java5.thread.newSkill; import java.util.Random;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock; /**
* 读写锁的案例
*/
public class ReadWriteLockTest { public static void main(String[] args) { final Queues queues = new Queues();
for ( int i = 0; i < 10; i++) {
final int j = i;
new Thread() {
public void run() {
//此处打标记A,下面注释会提到
/*if(j<10)*/ while(true){
queues.get();
}
}
}.start();
new Thread() {
public void run() {
/*if(j<10)*/while(true) {
queues.put(new Random().nextInt(10000));
}
}
}.start();
}
}
} class Queues {
// 共享数据;只能有一个线程能写改数据,但能有多个线程同时读数据
private Object data = null;
/*这里如果这么写:
* ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
上面的标记A处,如果用while(true)会一直写不读,但是如果不用while死循环则可以正确执行,
比如用if(i<10);目前还没找到原因,希望大牛们看到后指点迷津;
个人猜测:没有用面向接口编程,上锁后,死循环中的内容会无穷之的执行,执行不完不会开锁
*/
ReadWriteLock rwl = new ReentrantReadWriteLock(); // 读的方法,用的是读锁readLock()
public void get() {
rwl.readLock().lock();
try {
System.out.println(Thread.currentThread().getName()
+ " be ready to read data!");
Thread.sleep((long) Math.random() * 1000);
System.out.println(Thread.currentThread().getName()
+ " have read data:" + data);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
rwl.readLock().unlock();
}
} // 写的方法;用到写的锁:writeLock()
public void put(Object data) {
rwl.writeLock().lock();
try {
System.out.println(Thread.currentThread().getName()
+ " be ready to write data!");
Thread.sleep((long) Math.random() * 1000);
this.data = data;
System.out.println(Thread.currentThread().getName()
+ " have write data:" + data);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
rwl.writeLock().unlock();
}
}
}
4. 缓存系统的模拟编写;读写锁的实际应用价值
package com.java5.thread.newSkill; import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock; public class CacheDemo { /**
* 缓存系统的模拟编写;读写锁的实际应用价值
*/
private Map<String, Object> cache = new HashMap<String, Object>(); public static void main(String[] args) { } private ReadWriteLock rwl = new ReentrantReadWriteLock(); public Object getData(String key) {
//如果客户一来读取value数据,则在客户一进去后上一把读锁;防止其他客户再次进行读,产生并发问题
rwl.readLock().lock();
Object value = null;
try {
value = cache.get(key);
if (value == null) {
//如果如果读到的值为空则释放读锁,打开写锁,准备给value赋值
rwl.readLock().unlock();
rwl.writeLock().lock();
try {
//如果打开写锁还为空,则给value赋值aaa
if (value == null) {
value = "aaa"; //实际失去queryDB()
}
} finally {
//使用完写锁后关掉
rwl.writeLock().unlock();
}
//释放写锁后,再次打开读锁,供客户读取value的数据
rwl.readLock().lock();
}
} finally {
//最后客户一读完后释放掉读锁
rwl.readLock().unlock();
}
return value;
}
}
5.新技术condition案例分析;代替wait()和notify()方法
package com.java5.thread.newSkill; import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; /**
* 面试题: 子线程循环10次,接着主线程循环100次,接着又回到子线程循环10次, 接着再回到主线程又循环100次,如此循环50次,代码如下:
*
* 思路: 编写一个业务类,是为了不把自己绕进去,体现代码的的高聚类特性和代码的健壮性,
* 即共同数据(比如这里的同步锁)或共同算法的若干个方法都可以提到同一个类中编写
*
* 注意:wait()和notify()必须在synchronized关键字内使用;
* 因为this.watit()中用到的this是synchronized()括号内的
* 内容;如果不使用synchronized直接就用wait()会包状态不对的错误
*/
public class ConditionCommunication { public static void main(String[] args) {
final Business business = new Business();
new Thread(new Runnable() { @Override
public void run() {
for (int i = 1; i <= 50; i++) {
business.sub(i);
}
}
}).start(); for (int i = 1; i <= 50; i++) {
business.main(i);
} }
} // 编写一个有子方法(用来调用子线程)和主方法(调用主线程)的业务类 class Business {
private boolean bShouldSub = true;
Lock lock = new ReentrantLock();
// condition必须基于lock锁之上的
Condition condition = lock.newCondition(); public void sub(int i) {
try {
lock.lock();
while (!bShouldSub) {
try {
// this.wait();
/*
* condition使用的是await()注意与wait()的区别;
* 因为condition也是Object对象所以也可以调用wait()方法,所以千万别调错了
*/
condition.await();
} catch (Exception e) {
e.printStackTrace();
}
}
for (int j = 1; j <= 10; j++) {
System.out.println("sub thread sequence of " + j
+ " ,loop of " + i);
}
bShouldSub = false;
// this.notify();
condition.signal();
} finally {
lock.unlock();
}
} public void main(int i) {
/*
* 这里最好用while,但是跟if的效果一样,只是前者代码更健壮, while可以防止线程自己唤醒自己,即通常所说的伪唤醒;
* 相当于一个人做梦不是被别人叫醒而是自己做噩梦突然惊醒; 这时用while可以防止这种情况发生
*/
try {
lock.lock();
while (bShouldSub) {
try {
// this.wait();
condition.await();
} catch (Exception e) {
e.printStackTrace();
}
}
for (int j = 1; j <= 100; j++) {
System.out.println("main thread sequence of " + j
+ " ,loop of " + i);
}
bShouldSub = true;
// this.notify();
condition.signal();
} finally {
lock.unlock();
}
}
}
6. 多个Condition的应用场景;以下是三个condition通讯的代码:
package com.java5.thread.newSkill; import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; /**
* 多个Condition的应用场景
* 以下是三个condition通讯的代码:
*/
public class ThreeConditionCommunication { public static void main(String[] args) {
final Business business = new Business();
//线程2,老二线程
new Thread(new Runnable() { @Override
public void run() {
for (int i = 1; i <= 50; i++) {
business.sub(i);
}
}
}).start(); //线程3,老三线程
new Thread(new Runnable() { @Override
public void run() {
for (int i = 1; i <= 50; i++) {
business.sub2(i);
}
}
}).start(); //主线程1,老大线程
for (int i = 1; i <= 50; i++) {
business.main(i);
} } /*编写一个有子方法(用来调用子线程)和主方法(调用主线程)的业务类
* 这个项目下虽然有两个Business类;但是在不同包下所以不影响; 如果在同一包下,那么就要改名或者将其弄成内部类,如果又想要把他当外部类使用,
* 那么将其弄成static 静态的就可以了
*/
static class Business {
private int shouldSub = 1;
Lock lock = new ReentrantLock(); Condition condition1 = lock.newCondition();
Condition condition2 = lock.newCondition();
Condition condition3 = lock.newCondition(); public void sub(int i) {
try {
lock.lock();
while (shouldSub != 2) {
try {
condition2.await();
} catch (Exception e) {
e.printStackTrace();
}
}
for (int j = 1; j <= 10; j++) {
System.out.println("sub thread sequence of " + j
+ " ,loop of " + i);
}
shouldSub = 3;
condition3.signal();
} finally {
lock.unlock();
}
}
public void sub2(int i) {
try {
lock.lock();
while (shouldSub != 3) {
try {
condition3.await();
} catch (Exception e) {
e.printStackTrace();
}
}
for (int j = 1; j <= 10; j++) {
System.out.println("sub2 thread sequence of " + j
+ " ,loop of " + i);
}
shouldSub = 1;
condition1.signal();
} finally {
lock.unlock();
}
} public void main(int i) {
try {
lock.lock();
while (shouldSub != 1) {
try {;
condition1.await();
} catch (Exception e) {
e.printStackTrace();
}
}
for (int j = 1; j <= 100; j++) {
System.out.println("main thread sequence of " + j
+ " ,loop of " + i);
}
shouldSub = 2;
condition2.signal();
} finally {
lock.unlock();
}
}
}
}
线程高级应用-心得5-java5线程并发库中Lock和Condition实现线程同步通讯的更多相关文章
- 线程高级应用-心得7-java5线程并发库中阻塞队列Condition的应用及案例分析
1.阻塞队列知识点 阻塞队列重要的有以下几个方法,具体用法可以参考帮助文档:区别说的很清楚,第一个种方法不阻塞直接抛异常:第二种方法是boolean型的,阻塞返回flase:第三种方法直接阻塞. 2. ...
- 线程高级应用-心得8-java5线程并发库中同步集合Collections工具类的应用及案例分析
1. HashSet与HashMap的联系与区别? 区别:前者是单列后者是双列,就是hashmap有键有值,hashset只有键: 联系:HashSet的底层就是HashMap,可以参考HashSe ...
- 线程高级应用-心得4-java5线程并发库介绍,及新技术案例分析
1. java5线程并发库新知识介绍 2.线程并发库案例分析 package com.itcast.family; import java.util.concurrent.ExecutorServi ...
- Java中的线程--并发库中的集合
线程中的知识点基本都已经学完了,看看Java5并发库中提供的集合... 一.可堵塞队列 队列包含固定长度的队列和不固定长度的队列 ArrayBlockQueue中只有put()方法和take()方法才 ...
- Java 并发编程中的 Executor 框架与线程池
Java 5 开始引入 Conccurent 软件包,提供完备的并发能力,对线程池有了更好的支持.其中,Executor 框架是最值得称道的. Executor框架是指java 5中引入的一系列并发库 ...
- Java 并发编程中的 CyclicBarrier 用于一组线程互相等待
Java 5 引入的 Concurrent 并发库软件包中的 CyclicBarrier 是一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point) ...
- Java中的线程--Lock和Condition实现线程同步通信
随着学习的深入,我接触了更多之前没有接触到的知识,对线程间的同步通信有了更多的认识,之前已经学习过synchronized 实现线程间同步通信,今天来学习更多的--Lock,GO!!! 一.初时Loc ...
- 线程高级应用-心得6-java5线程并发库中同步工具类(synchronizers),新知识大用途
1.新知识普及 2. Semaphore工具类的使用案例 package com.java5.thread.newSkill; import java.util.concurrent.Executor ...
- 细数Android开源项目中那些频繁使用的并发库中的类
这篇blog旨在帮助大家 梳理一下前面分析的那些开源代码中喜欢使用的一些类,这对我们真正理解这些项目是有极大好处的,以后遇到类似问题 我们就可以自己模仿他们也写 出类似的代码. 1.ExecutorS ...
随机推荐
- mysqldump备份过程中都干了些什么
mysqldump备份方便,易读,功能丰富,相信大家都有 使用过这个命令进行备份,但是这个命令在备份的过程中都做了写什么呢,下面打开general_log进行查看: 1.登录mysql命令行客户端: ...
- char 型变量中能不能存贮一个中文汉字,为什么?
char类型可以存储一个中文汉字,因为Java中使用的编码是Unicode(不选择任何特定的编码,直接使用字符在字符集中的编号,这是统一的唯一方法),一个char类型占2个字节(16比特),所以放一个 ...
- ArrayList集合的实现原理
一. ArrayList概述: ArrayList是基于数组实现的,是一个动态数组,其容量能自动增长,类似于C语言中的动态申请内存,动态增长内存. ArrayList不是线程安全的,只能用在单线程环境 ...
- js笔记---封装自己的Ajax方法
//地址 成功方法 失败方法function Ajax(url, funsucc, funfial) { var oAjax = null; if (window.XMLHttpRequest) { ...
- c# UDP通信
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...
- PHP之缩略图
<?php $imagefile="C:\\Users\\Administrator\\Desktop\\2.jpeg"; $imagattr=getimagesize($i ...
- ACM-ICPC国际大学生程序设计竞赛北京赛区(2016)网络赛 A Simple Job
描述 Institute of Computational Linguistics (ICL), Peking University is an interdisciplinary institute ...
- 如何把drawing图像转换成wpf控件的source
此例以canvas为例 <Canvas> <Image Stretch="Fill" Width="100" Height="10 ...
- (3)redis队列功能
Redis队列功能介绍 List 常用命令: Blpop删除,并获得该列表中的第一元素,或阻塞,直到有一个可用 Brpop删除,并获得该列表中的最后一个元素,或阻塞,直到有一个可用 Brpoplpus ...
- [cdoj1380] Xiper的奇妙历险(3) (八数码问题 bfs + 预处理)
快要NOIP 2016 了,现在已经停课集训了.计划用10天来复习以前学习过的所有内容.首先就是搜索. 八数码是一道很经典的搜索题,普通的bfs就可求出.为了优化效率,我曾经用过康托展开来优化空间,甚 ...