java并发编程系列三、Lock和Condition
有了synchronized为什么还要Lock?
因为Lock和synchronized比较有如下优点
1、 尝试非阻塞地获取锁
2、 获取锁的过程可以被中断
3、 超时获取锁
Lock的标准用法
package com.lgs; import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; /**
* lgs
* 显示锁lock的标准写法
*/
public class LockTemplete { public static void main(String[] args) {
Lock lock = new ReentrantLock();
//获取锁
lock.lock();
try{
// do my work.....
}finally{
//释放锁
lock.unlock();
}
} }
Lock的常用方法
Lock() 获取锁
tryLock尝试非阻塞地获取锁
lockInterruptibly:获取锁的过程可以被中断
tryLock(long time, TimeUnit unit) 超时获取锁
unlock()释放锁
锁的可重入
一个线程获得了锁进入了同步代码块遇到了锁仍然可以进入同步代码块
递归的时候发生锁的重入,没有锁的可重入,就会死锁
公平和非公平锁
公平锁,先对锁发出获取请求的一定先被满足。公平锁的效率比非公平锁效率要低。
为什么非公平锁的性能要高:因为非公平锁是可以插队的,如线程C被唤醒变为可执行去获取锁的过程中,线程A插队进来直接获取锁执行自己的业务,线程A执行完以后,线程C刚好唤醒完直接就获取锁运行了,这样在线程C唤醒的过程中线程A就执行完了效率更高
读写锁ReentrantReadWriteLock
允许多个读线程同时进行,但是只允许一个写线程(不允许其他读线程防止脏读和写线程),支持读多写少场景,性能会有提升。
package com.lgs; import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock; /**
* lgs
* 读写锁的使用
*/
public class RwLockTemplete { static final Map<String,String> map = new HashMap<>();
static ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();
static Lock r = reentrantReadWriteLock.readLock();
static Lock w = reentrantReadWriteLock.writeLock(); public void put(){
w.lock();
try{
// do my work.....
}finally{
w.unlock();
}
} public void get(){
r.lock();
try{
// do my work.....
}finally{
r.unlock();
}
} }
Condition接口有何用处?
Object的 wait,notify/notifyAll 实现等待通知机制
Condition接口和Lock配合来实现等待通知机制
Condition常用方法和使用范式
package com.lgs; import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; /**
* lgs
* Condition的使用方式
*/
public class ConditionTemplete { Lock lock = new ReentrantLock();
Condition condition = lock.newCondition(); public void waitc() throws InterruptedException {
lock.lock();
try{
condition.await();
}finally{
lock.unlock();
}
} public void waitnotify() throws InterruptedException {
lock.lock();
try{
condition.signal();
//condition.signalAll();尽量少使用
}finally{
lock.unlock();
}
} }
结合ReentrantLock和Condition实现线程安全的有界队列
package com.lgs.bq; import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; /**
* lgs
* 结合ReentrantLock和Condition实现线程安全的有界队列
*/
public class BlockingQueueLC<T> {
private List queue = new LinkedList<>();
private final int limit;
Lock lock = new ReentrantLock();
private Condition needNotEmpty = lock.newCondition();
private Condition needNotFull = lock.newCondition(); public BlockingQueueLC(int limit) {
this.limit = limit;
} public void enqueue(T item) throws InterruptedException {
lock.lock();
try{
while(this.queue.size()==this.limit){
needNotFull.await();
}
this.queue.add(item);
//通知出队线程有数据可以取了
needNotEmpty.signal();
}finally{
lock.unlock();
}
} public T dequeue() throws InterruptedException {
lock.lock();
try{
while(this.queue.size()==0){
needNotEmpty.await();
}
//通知入队线程有位置可以入队了
needNotFull.signal();
return (T) this.queue.remove(0);
}finally{
lock.unlock();
}
}
}
package com.lgs.bq; /**
*
*/
public class BqTest {
public static void main(String[] args) {
BlockingQueueLC<Integer> bq = new BlockingQueueLC(10);
Thread threadA = new ThreadPush(bq);
threadA.setName("Push");
Thread threadB = new ThreadPop(bq);
threadB.setName("Pop");
threadB.start();
threadA.start();
} private static class ThreadPush extends Thread{
BlockingQueueLC<Integer> bq; public ThreadPush(BlockingQueueLC<Integer> bq) {
this.bq = bq;
} @Override
public void run() {
String threadName = Thread.currentThread().getName();
int i = 5;
while(i>0){
try {
Thread.sleep(500);
System.out.println(" i="+i+" will push");
bq.enqueue(i--);
} catch (InterruptedException e) {
//e.printStackTrace();
} }
}
} private static class ThreadPop extends Thread{
BlockingQueueLC<Integer> bq; public ThreadPop(BlockingQueueLC<Integer> bq) {
this.bq = bq;
}
@Override
public void run() {
while(true){
try {
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName()+" will pop.....");
Integer i = bq.dequeue();
System.out.println(" i="+i.intValue()+" alread pop");
} catch (InterruptedException e) {
//e.printStackTrace();
}
} }
}
}
java并发编程系列三、Lock和Condition的更多相关文章
- Java并发编程系列-(5) Java并发容器
5 并发容器 5.1 Hashtable.HashMap.TreeMap.HashSet.LinkedHashMap 在介绍并发容器之前,先分析下普通的容器,以及相应的实现,方便后续的对比. Hash ...
- Java并发编程系列-(4) 显式锁与AQS
4 显示锁和AQS 4.1 Lock接口 核心方法 Java在java.util.concurrent.locks包中提供了一系列的显示锁类,其中最基础的就是Lock接口,该接口提供了几个常见的锁相关 ...
- Java并发编程系列-(1) 并发编程基础
1.并发编程基础 1.1 基本概念 CPU核心与线程数关系 Java中通过多线程的手段来实现并发,对于单处理器机器上来讲,宏观上的多线程并行执行是通过CPU的调度来实现的,微观上CPU在某个时刻只会运 ...
- 干货:Java并发编程系列之volatile(二)
接上一篇<Java并发编程系列之synchronized(一)>,这是第二篇,说的是关于并发编程的volatile元素. Java语言规范第三版中对volatile的定义如下:Java编程 ...
- Java并发编程系列-(6) Java线程池
6. 线程池 6.1 基本概念 在web开发中,服务器需要接受并处理请求,所以会为一个请求来分配一个线程来进行处理.如果每次请求都新创建一个线程的话实现起来非常简便,但是存在一个问题:如果并发的请求数 ...
- Java并发编程系列-(7) Java线程安全
7. 线程安全 7.1 线程安全的定义 如果多线程下使用这个类,不过多线程如何使用和调度这个类,这个类总是表示出正确的行为,这个类就是线程安全的. 类的线程安全表现为: 操作的原子性 内存的可见性 不 ...
- Java并发编程系列-(8) JMM和底层实现原理
8. JMM和底层实现原理 8.1 线程间的通信与同步 线程之间的通信 线程的通信是指线程之间以何种机制来交换信息.在编程中,线程之间的通信机制有两种,共享内存和消息传递. 在共享内存的并发模型里,线 ...
- 原创】Java并发编程系列2:线程概念与基础操作
[原创]Java并发编程系列2:线程概念与基础操作 伟大的理想只有经过忘我的斗争和牺牲才能胜利实现. 本篇为[Dali王的技术博客]Java并发编程系列第二篇,讲讲有关线程的那些事儿.主要内容是如下这 ...
- [Java并发编程(三)] Java volatile 关键字介绍
[Java并发编程(三)] Java volatile 关键字介绍 摘要 Java volatile 关键字是用来标记 Java 变量,并表示变量 "存储于主内存中" .更准确的说 ...
随机推荐
- luogu1972 HH的项链(树状数组)
无修改.询问区间种类数的问题可以很容易地用树状数组解决 我们先给询问按右端点排序,然后推着做,每次让a[i]++,表示i处新增了一个种类 但是这样会和前面的有重复,我们只要记下每个种类上次在哪里出现过 ...
- JSP总结(一)——基础(汇总)
前言:原本呢,是打算只写个JSP的内置对象总结,但是没想到这个家伙的JSP总结非常不错,我就拿来用了. 注:后缀为汇总的基本上是整理一些网上的. 借鉴地址:http://www.cnblogs.com ...
- linux提取指定列字符并打印所有内容(awk)
假设有文件长如下样子: CHROM POS ID REF ALT QUAL FILTER INFO FORMAT samplename 1 3552 ...
- Druid数据源对数据库访问密码加密好麻烦
开发中,druid数据源对数据库密码进行了加密,每次切换数据库或者修改密码后,感觉很麻烦. 解决办法: 1.用工具类中的Java代码进行加解密. 需要用到com.alibaba.druid.filte ...
- 字节流转字符流OutputStreamWriter、InputStreamReader,关闭流的方法
转换时可以指定编码格式:GBK.UTF-8 public class Demo { public static void main(String[] args) { File f = new File ...
- Python协程笔记 - yield
生成器(yield)作为协程 yield实际上是生成器,在python 2.5中,为生成器增加了.send(value)方法.这样调用者可以使用send方法对生成器发送数据,发送的数据在生成器中会赋值 ...
- python字典遍历的几种方法
(1)遍历key值 >>> a {'} >>> for key in a: print(key+':'+a[key]) a:1 b:2 c:3 >> ...
- django 403问题
C:\Users\x\pyp1>python manage.py runserverPerforming system checks... System check identified no ...
- Bandicam录制视频
我已经录制了一个视频,关于怎么录制视频的,原画画质的嘻嘻.视频地址 http://www.tudou.com/programs/view/T7xzG1CgsD4 ------------------ ...
- 在tomcat集群下利用redis实现单点登陆
场景:比如说我们要实现一个集群环境,无非是把多个项目部署到多个tomcat下,然后按照一定的算法,轮询什么的随机访问多个tomcat服务器,但是问题也会有许多,比如说,我们最开始是把登陆人的信息存放到 ...