定义:
独占锁是一种悲观保守的加锁策略,它避免了读/读冲突,如果某个只读线程获取锁,则其他读线程都只能等待,这种情况下就限制了不必要的并发性,因为读操作并不会影响数据的一致性。
共享锁则是一种乐观锁,它放宽了加锁策略,允许多个执行读操作的线程同时访问共享资源。
分类:
独占锁: ReentrantLock, ReentrantReadWriteLock.WriteLock
共享锁:ReentrantReadWriteLock.ReadLock,CyclicBarrier, CountDownLatch和Semaphore都是共享锁
其他:
wait(), notify() @hxx,对应Contition的 await 和 signal
前者是object,在代码中用锁对象即可调用,后者是一个即可,必须使用ReentrantLock生成
final Lock lock = new ReentrantLock();
final Condition notFull = lock.newCondition();
final Condition notEmpty = lock.newCondition();
Synchronized
ReentrantLock是Synchronized一种更高级的改进
1: 更加面向对象,性能更好
2: 提供了更多机制,比如时间锁等候,可中断锁等候,锁投票等
3: ReentrantLock提供了可轮询的锁请求,提供tryLock()方法;而synchronized则会一直阻塞等待
Lock lock = ...;
if (lock.tryLock()) {
try {
// manipulate protected state
} finally {
lock.unlock();
}
} else {
// 资源正在被别人写,先做别的事情吧,比如说打印一行日志
}
注意事项:
除了Synchronized自动走出锁范围,其余占有了锁,一定要记得释放锁,可以在finally中释放!!!!
公平参数,默认都是关闭的,所以不要以为等的时间越长就能更大几率获得锁!公平和非公平对应着:公平锁和非公平锁(Sync类的两个子类),非公平锁无视等待队列,直接上来就是抢!
java实现锁的底层都是使用Sync类,private final Sync sync;  
是继承了AbstractQueuedSynchronizer的内部抽象类,主要由它负责实现锁的功能。关于 AbstractQueuedSynchronizer 只要知道它内部存在一个获取锁的等待队列及其互斥锁状态下的int状态位(0当前没有线程持有该锁、n存在某线程重入锁n次)即可,该状态位也可用于其它诸如共享锁、信号量等功能。
----------------------------------------
Demo code:
1: CountDownLatch
用于n个线程等待其余M个线程结束, 类位于java.util.concurrent包下
代码:
CountDownLatch doneSignal = new CountDownLatch(3); // 定义了计数器为3.表示有3个线程结束即可!
for(int i=0; i<5; i++)
new InnerThread().start(); // m个线程,InnerThread的run方法末尾中写了doneSignal .countDown(); 必须手动减
doneSignal.await(); // 阻塞,直到3个线程结束
//  await(long timeout, TimeUnit unit) throws InterruptedException { }; 这个就可以实现超时功能
2: CyclicBarrier
java.util.concurrent包,实现 M 个线程在barrier栅栏处互相等待,可以重用状态(所以叫cycli),1的计数器只能减不能重新赋值!
代码:
CyclicBarrier barrier = new CyclicBarrier(N);// N个线程互相等
for(int i=0;i<N;i++)
new Writer(barrier).start(); // Writer的run方法需要M个线程一起完成的点中写了barrier.await();
 
3: Semaphore
java.util.concurrent包,用于限制最多M个线程同时并发
代码:
int N = 8; //工人数
Semaphore semaphore = new Semaphore(5); //机器数目, 限制了最多5个并发, 默认是不公平的构造可以加true
for(int i=0;i<N;i++)
new Worker(i,semaphore).start();
@Override
public void run() {
try {
semaphore.acquire(); // 拿凭证,总共5张凭证,没拿到会阻塞, 不想阻塞可用tryAcquire
System.out.println("工人"+this.num+"占用一个机器在生产...");
Thread.sleep(2000);
System.out.println("工人"+this.num+"释放出机器");
semaphore.release(); // 释放凭证
} catch (InterruptedException e) {
e.printStackTrace();
}
}
4: ReentrantLock
java.util.concurrent包,用于实现同步功能,与synchronized相似但是面向对象更灵活
ReentrantLock takeLock = new ReentrantLock();
// 获取锁
takeLock.lock();
try {
// 业务逻辑
} finally {
// 释放锁
takeLock.unlock();
}
5: ReentrantReadWriteLock
4是其父类,根据名字可以看到这个类区分了读写锁,与4的优势是线程大多在数据结构中读取数据而少有修改时这个就有用了。
读写锁要实现的功能是三点: 多个读互相不干扰;多个写操作必须独占锁;读和写操作要上锁!(@hxx第一个分号我我为什么要用黑色,因为这就是读写锁出现的意义,提升了读的性能,不然就用4了)
如何实现的呢? 看先代码!
以下这段代码来自jdk文档中demo,写的非常好!!
class CachedData { Object data; volatile boolean cacheValid; ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); void processCachedData() { rwl.readLock().lock(); //step1 @hxx 任何人都可以读数据,因为没人写,提高性能 if (!cacheValid) { // @hxx 如果有缓存了,就不用去load数据库写缓存了,相当于if(cache.get(key) == null) // Must release read lock before acquiring write lock rwl.readLock().unlock(); // @hxx 为什么 拿“写锁” 前要释放掉 “读锁”?? 要判断没有人拿 “读锁” 才可以写吗,是这样实现读写互斥的吗? 如果是,那么我在这里不释放,是不是就违背了机制,try后,确实是的 rwl.writeLock().lock();
// @hxx 从这里开始,保证一次只有一个线程进来啦 begin!! // Recheck state because another thread might have acquired // write lock and changed state before we did. if (!cacheValid) { data = ... cacheValid = true; } // Downgrade by acquiring read lock before releasing write lock
// @hxx,我先那个读锁,哈哈, 在我释放读锁之前,谁也别想拿写锁,因为写锁拿到的前提是没有人拿读锁 rwl.readLock().lock(); rwl.writeLock().unlock(); // Unlock write, still hold read
// @hxx 从这里开始,保证一次只有一个线程进来啦 end!! } use(data); // step2 @hxx 我在读数据不怕别人写,真的爽! rwl.readLock().unlock(); // @hxx 现在我释放了读锁,去拿写锁吧! } }
ps: 上面代码。缓存一旦初始化成功后,后续的逻辑就只会走step1 + step2 了,就只有读锁共享了!
6: ReentrantReadWriteLock.ReadLock 和ReentrantReadWriteLock.WriteLock
看jdk文档里面。以为又是一个新的东西,其实就是5中代码
ReentrantReadWriteLock.writeLock() 返回的对象
ReentrantReadWriteLock.readLock() 返回的对象
略过
7: wait(), notify()
java.lang.Object 的方法
8: Condition接口 (需要与ReentrantLock配合使用)
条件变量很大一个程度上是为了解决Object.wait/notify/notifyAll难以使用的问题,@hxx也就是消费者生产者代码中判断队列是否满,是否空的条件!
代码如下:
final Lock lock = new ReentrantLock();
final Condition notFull = lock.newCondition();
final Condition notEmpty = lock.newCondition();
 
private Queue<Integer> buffer = new LinkedList<>();
int max = 100;
int putptr, takeptr, count;
 
public void put(Object x) throws InterruptedException {
lock.lock();// 先拿锁
try {
while (max == buffer.size())
notFull.await();
// 不满,则可以放
buffer.add(1);
// 提醒可以取
notEmpty.signal();
} finally {// 记得释放锁
lock.unlock();
}
}
 
public Object take() throws InterruptedException {
lock.lock();
try {
while (count == 0)
notEmpty.await();
//不空, 可以取
int x= buffer.poll();
// 提醒可放
notFull.signal();
return x;
} finally {
lock.unlock();
}
}

java高并发总结-常用于面试复习的更多相关文章

  1. Java高并发--原子性可见性有序性

    Java高并发--原子性可见性有序性 主要是学习慕课网实战视频<Java并发编程入门与高并发面试>的笔记 原子性:指一个操作不可中断,一个线程一旦开始,直到执行完成都不会被其他线程干扰.换 ...

  2. Java高并发综合

    这篇文章是研一刚入学时写的,今天整理草稿时才被我挖出来.当时混混沌沌的面试,记下来了一些并发的面试问题,很多还没有回答.到现在也学习了不少并发的知识,回过头来看这些问题和当时整理的答案,漏洞百出又十分 ...

  3. 2017.4.26 慕课网--Java 高并发秒杀API(一)

    Java高并发秒杀API系列(一) -----------------业务分析及Dao层 第一章 课程介绍 1.1 内容介绍及业务分析 (1)课程内容 SSM框架的整合使用 秒杀类系统需求理解和实现 ...

  4. Java高并发与多线程(四)-----锁

    今天,我们开始Java高并发与多线程的第四篇,锁. 之前的三篇,基本上都是在讲一些概念性和基础性的东西,东西有点零碎,但是像文科科目一样,记住就好了. 但是本篇是高并发里面真正的基石,需要大量的理解和 ...

  5. Java高并发如何解决

    Java高并发如何解决 对于我们开发的网站,如果网站的访问量非常大的话,那么我们就需要考虑相关的并发访问问题了.而并发问题是绝大部分的程序员头疼的问题,但话又说回来了,既然逃避不掉,那我们就坦然面对吧 ...

  6. Java高并发的常见应对方案

    Java高并发的常见应对方案 一.关于并发我们说的高并发是什么? 在互联网时代,高并发,通常是指,在某个时间点,有很多个访问同时到来. 高并发,通常关心的系统指标与业务指标? QPS:每秒钟查询量,广 ...

  7. Java高并发--消息队列

    Java高并发--消息队列 主要是学习慕课网实战视频<Java并发编程入门与高并发面试>的笔记 举个例子:在购物商城下单后,希望购买者能收到短信或者邮件通知.有一种做法时在下单逻辑执行后调 ...

  8. Java高并发--缓存

    Java高并发--缓存 主要是学习慕课网实战视频<Java并发编程入门与高并发面试>的笔记 在下图中每一个部分都可以使用缓存的技术. 缓存的特征 缓存命中:直接通过缓存获取到数据 命中率: ...

  9. Java高并发 -- 并发扩展

    Java高并发 -- 并发扩展 主要是学习慕课网实战视频<Java并发编程入门与高并发面试>的笔记 死锁 死锁是指两个或两个以上的事务在执行过程中,因争夺锁资源而造成的一种互相等待的现象, ...

随机推荐

  1. OOP的感悟

    不要认为你关心的东西就是对象的全部或对象的核心,相对于对象的成员家族而言,它仅仅是其中的一个‘很小的成员而已’

  2. 物理内存不够用,临时增大Linux交换分区的方法

    当系统的物理内存不够用的时候,就需要将物理内存中的一部分空间释放出来,以供当前运行的程序使用.那些被释放的空间可能来自一些很长时间没有什么 操作的程序,这些被释放的空间被临时保存到Swap空间中,等到 ...

  3. 『转』Dr.Web Security Space 8 – 免费3个月

    简短的测试五个问题,任意回答问题,都将获得Dr.Web Security Suite 3个月免费许可证以及大蜘蛛企业安全套件2个月来保护整个公司!活动地址:https://www.drweb.com/ ...

  4. Alpha阶段第1周Scrum立会报告+燃尽图 04

    作业要求与https://edu.cnblogs.com/campus/nenu/2018fall/homework/2246相同 一.小组介绍 组长:刘莹莹 组员:朱珅莹 孙韦男 祝玮琦 王玉潘 周 ...

  5. (转)Fiddler教程(Web调试工具)

    转载地址:写得很不错的fildder教程   http://kb.cnblogs.com/page/130367/ Fiddler的基本介绍 Fiddler的官方网站:  www.fiddler2.c ...

  6. Jenkins配置slave遇到“无法启动该应用程序”的问题

    飞测说:最近在负责持续集成相关的工作,我们用的是jenkins+svn+maven+sonar, 今天在用slave这块出现了一个问题,排查了好久才解决,踩过的坑,现在和大家一起看看,希望对大家有帮助 ...

  7. JQ深度手记、源码分析

    1.$.extend() 对象继承操作.浅拷贝操作.深拷贝操作(第一个参数:true) var a = { name:'lisan' }; var b = {}; $.extend(b, a); // ...

  8. (转)类的sizeof

    来源:http://www.360doc.com/content/12/0315/17/3349869_194600377.shtml

  9. brave-zipkin的日志源码分析

    其实在zipkin的日志里面作为发送端日志两个,sr,ss,这个日志是servlet产生的:接收端日志是四个,分别是cr,sr,ss,cs:cr和cs分别是上游的日志的信息:ss和sr是接收端输出的日 ...

  10. 基于Tomcat 的WEB Project存在的安全漏洞总结

    1 检查工具:Acunetix Web Vulnerability Scanner V9破解版 2 检查漏洞说明结果显示: 2.1 HTML Form Without CSRF Protection ...