线程高级应用-心得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 ...
随机推荐
- java 数组基本操作(一维)
1.数组的声明: 数组类型 数组名[] 2.数组的表示方法 想使用数组中的值,可以使用索引来实现,数组是从0开始的,使用时格式为:数组名[i],比如 a[1],代表第二个值 在数组中要使用数组的长度 ...
- jar的下载地址及其使用说明
有时候会苦于jar的搜索.这里我就给出我平时用到的吧,方便大家.后期会不断添加. 1.dom4j-1.6.1.jar 主要用于解析xml的jar包.下载地址: http://pan.baidu.c ...
- JDBC批量Insert深度优化(有事务)
环境: MySQL 5.1 RedHat Linux AS 5 JavaSE 1.5 DbConnectionBroker 微型数据库连接池 测试的方案: 执行10万次Insert语句,使用不同方 ...
- php获取json文件数据并动态修改网站头部文件meta信息 --基于CI框架
话不多说了.直接开始吧 (如果有中文.请注意json只认utf-8编码) 首先你需要有一个json文件数据 { "index": { ...
- 滑雪 分类: POJ 2015-07-23 19:48 9人阅读 评论(0) 收藏
滑雪 Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 83276 Accepted: 31159 Description Mich ...
- 2016 ACM/ICPC Asia Regional Qingdao Online HDU5882
链接:http://acm.hdu.edu.cn/showproblem.php?pid=5882 解法:一个点必须出度和入度相同就满足题意,所以加上本身就是判断奇偶性 #include<std ...
- Mysql-学习笔记(==》触发器 十一)
-------触发器-------- USE db;SELECT FROM sss; CREATE TABLE sssbak LIKE sss;SHOW CREATE TABLE sss;SHOW C ...
- 【Java】斐波那契数列(Fibonacci Sequence、兔子数列)的3种计算方法(递归实现、递归值缓存实现、循环实现、尾递归实现)
斐波那契数列:0.1.1.2.3.5.8.13………… 他的规律是,第一项是0,第二项是1,第三项开始(含第三项)等于前两项之和. > 递归实现 看到这个规则,第一个想起当然是递归算法去实现了, ...
- Python3基础 print 中使用+号,连接两个字符串
镇场诗:---大梦谁觉,水月中建博客.百千磨难,才知世事无常.---今持佛语,技术无量愿学.愿尽所学,铸一良心博客.------------------------------------------ ...
- serialVersionUID
serialVersionUID作用: 序列化时为了保持版本的兼容性,即在版本升级时反序列化仍保持对象的唯一性. 有两种生成方式: 一个是默认的1L,比如:private static final l ...