Lock接口

它提供3个常用的锁

lock() : 获不到锁就就一直阻塞

trylock() :获不到锁就立刻放回 或者 定时的,轮询的获取锁 

lockInterruptibly() : 获不到锁时阻塞,但可接受中断信号后退出阻塞状态

ReentrantLock

实现机制

基于冲突的乐观并发策略:

如果共享数据被争用,产生了冲突,那就再进行其他的补偿措施,比如说定时的获取锁,直到成功;不需要把线程挂起,也称为非阻塞的同步

公平性

公平: 多个线程在等待同一个锁时,必须按照申请锁的时间顺序排队等待
非公平: 在锁释放时,任何一个等待锁的线程都有机会获得锁,ReentrantLock构造方法,默然是非公平的

什么时候使用

当你需要可定时的和可中断的锁操作,公平队列,或者非块结构的锁,否则请使用synchronized

可中断的例子

public class MyReentrantLock {
private ReentrantLock lock = new ReentrantLock(); public void write() {
lock.lock();
try {
long startTime = System.currentTimeMillis();
System.out.println("开始往这个buff写入数据…");
for (;;)// 模拟要处理很长时间
{
if (System.currentTimeMillis() - startTime > Integer.MAX_VALUE) {
break;
}
}
System.out.println("终于写完了");
} finally {
lock.unlock();
}
} public void read() throws InterruptedException {
lock.lockInterruptibly();// 注意这里,可以响应中断
try {
System.out.println("从这个buff读数据");
} finally {
lock.unlock();
}
} public static void main(String args[]) {
MyReentrantLock buff = new MyReentrantLock(); final Writer2 writer = new Writer2(buff);
final Reader2 reader = new Reader2(buff); writer.start();
reader.start(); new Thread(new Runnable() { @Override
public void run() {
long start = System.currentTimeMillis();
for (;;) {
if (System.currentTimeMillis() - start > 5000) {
System.out.println("不等了,尝试中断");
reader.interrupt(); //此处中断读操作
break;
}
}
}
}).start(); }
} class Reader2 extends Thread { private MyReentrantLock buff; public Reader2(MyReentrantLock buff) {
this.buff = buff;
} @Override
public void run() { try {
buff.read();//可以收到中断的异常,从而有效退出
} catch (InterruptedException e) {
System.out.println("我不读了");
} System.out.println("读结束"); }
} class Writer2 extends Thread { private MyReentrantLock buff; public Writer2(MyReentrantLock buff) {
this.buff = buff;
} @Override
public void run() {
buff.write();
}
}

控制台输出:

开始往这个buff写入数据…
不等了,尝试中断
我不读了
读结束

ReentrantReadWriteLock读写锁

特点

互斥:它使得读写操作互斥,读读操作不互斥

锁降级:写线程获取写入锁后可以获取读取锁,然后释放写入锁,这样就从写入锁变成了读取锁

少写多读的例子

public class MyReadWriteLock {
public static void main(String[] args) {
PricesInfo pricesInfo = new PricesInfo();
Writer writer=new Writer(pricesInfo);
Reader read = new Reader(pricesInfo); //写线程
Thread tw=new Thread(writer);
tw.start(); //多个读线程
for (int i=0; i<5; i++){
Thread tr=new Thread(read);
tr.start();
}
}
} //读线程
class Reader implements Runnable{
private PricesInfo pricesInfo; public Reader(PricesInfo pricesInfo){
this.pricesInfo = pricesInfo;
} @Override
public void run() {
pricesInfo.getPrice();
}
} //写线程
class Writer implements Runnable{
private PricesInfo pricesInfo; public Writer(PricesInfo pricesInfo){
this.pricesInfo = pricesInfo;
} @Override
public void run() {
pricesInfo.setPrice(Math.random()*10); }
} //数据实体
class PricesInfo {
private double price; private ReadWriteLock lock = new ReentrantReadWriteLock(); public PricesInfo(){
} //读锁
public void getPrice(){
lock.readLock().lock();
System.out.println(Thread.currentThread().getName()+ " : in read*****************************");
System.out.println(Thread.currentThread().getName()+ ": 读取数据= " + price);
lock.readLock().unlock();
} //写锁
public void setPrice(double price){
lock.writeLock().lock();
try {
System.out.println(Thread.currentThread().getName()+ " :in Writer==============================================");
Thread.sleep(1000);
this.price = price;
System.out.println(Thread.currentThread().getName()+ ":写入数据= " + price);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.writeLock().unlock();
}
}
}

控制台输出:

Thread-0 :in Writer==============================================
Thread-0:写入数据= 3.5843085966236266
Thread-3 : in read*****************************
Thread-3: 读取数据= 3.5843085966236266
......

Condition条件变量

通过ReentrantLock的newCondition()得到Condition对象,它用await()替换wait(),用signal()替换 notify(),用signalAll()替换notifyAll(), 实现线程间的通信;

如果是公平锁,与Condition关联的任务,以FIFO的形式获取锁,否则的话,是随机获取锁;

消费者和生产者的例子

public class MyCondition{
public static void main(String args[]){
Info info = new Info(); //启动生产者
Producer pro = new Producer(info) ;
new Thread(pro).start() ; try{
Thread.sleep(100) ;
}catch(InterruptedException e){
e.printStackTrace() ;
} //启动消费者
Consumer con = new Consumer(info) ;
new Thread(con).start() ;
}
} class Info{ // 定义信息类
private String name = null;
private String content = null ;
private boolean flag = true ; // true生产, false消费 private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition(); //产生一个Condition对象 public void set(String name,String content){
lock.lock();
try{
while(!flag){
condition.await() ;
} this.setName(name) ; Thread.sleep(300) ; this.setContent(content) ;
flag = false ; // 改变标志位,表示可以取走 System.out.println("生产者: " + this.getName() + " --> " + this.getContent()) ; condition.signal();
}catch(InterruptedException e){
e.printStackTrace() ;
}finally{
lock.unlock();
}
} public void get(){
lock.lock();
try{
while(flag){
condition.await() ;
} Thread.sleep(300) ; System.out.println("消费者: " + this.getName() + " --> " + this.getContent()) ; flag = true ; // 改变标志位,表示可以生产 condition.signal();
}catch(InterruptedException e){
e.printStackTrace() ;
}finally{
lock.unlock();
}
} public void setName(String name){
this.name = name ;
}
public void setContent(String content){
this.content = content ;
}
public String getName(){
return this.name ;
}
public String getContent(){
return this.content ;
}
} /**生产者线程 */
class Producer implements Runnable{
private Info info = null ; // 保存Info引用 public Producer(Info info){
this.info = info ;
} public void run(){
boolean flag = true ; // 定义标记位
for(int i=0;i<10;i++){
if(flag){
this.info.set("姓名--1","内容--1") ;
flag = false ;
}else{
this.info.set("姓名--2","内容--2") ;
flag = true ;
}
}
}
} /**消费者线程 */
class Consumer implements Runnable{
private Info info = null ; public Consumer(Info info){
this.info = info ;
}
public void run(){
for(int i=0;i<10;i++){
this.info.get() ;
}
}
}

AQS 和 CAS

AQS : JUC基础类

state : 获取锁的标志

NOde{} : 获取锁的线程
SHARED : 共享锁
EXCLUSIVE : 互斥锁

CLH同步队列

LockSupport.park() 和 LockSupport.unpark() :阻塞和唤醒

CAS: JUC基础理论

对内存中共享数据进行操作的指令集, 自动更新共享数据, 代替了锁

内存值V,旧的预期值A,要修改的新值B。当且仅A和内存值V相同时,将内存值V修改为B,否则什么都不做

ABA问题

因为CAS需要在操作值的时候检查下值有没有发生变化,如果没有发生变化则更新,但是如果一个值原来是A,变成了B,又变成了A,那么使用CAS进行检查时会发现它的值没有发生变化,但是实际上却变化了。ABA问题的解决思路就是使用版本号。在变量前面追加上版本号,每次变量更新的时候把版本号加一,那么A-B-A 就会变成1A-2B-3A

Java并发编程--3.Lock的更多相关文章

  1. 【多线程】Java并发编程:Lock(转载)

    原文链接:http://www.cnblogs.com/dolphin0520/p/3923167.html Java并发编程:Lock 在上一篇文章中我们讲到了如何使用关键字synchronized ...

  2. [转载] java并发编程:Lock(线程锁)

    作者:海子 原文链接: http://www.cnblogs.com/dolphin0520/p/3923167.html 出处:http://www.cnblogs.com/dolphin0520/ ...

  3. Java并发编程:Lock(转)

    本文转自:http://www.cnblogs.com/dolphin0520/p/3923167.html Java并发编程:Lock 在上一篇文章中我们讲到了如何使用关键字synchronized ...

  4. 5、Java并发编程:Lock

    Java并发编程:Lock 在上一篇文章中我们讲到了如何使用关键字synchronized来实现同步访问.本文我们继续来探讨这个问题,从Java 5之后,在java.util.concurrent.l ...

  5. 【java并发编程】Lock & Condition 协调同步生产消费

    一.协调生产/消费的需求 本文内容主要想向大家介绍一下Lock结合Condition的使用方法,为了更好的理解Lock锁与Condition锁信号,我们来手写一个ArrayBlockingQueue. ...

  6. 【转】Java并发编程:Lock

    阅读目录 一.synchronized的缺陷 二.java.util.concurrent.locks包下常用的类 三.锁的相关概念介绍 来自: http://www.importnew.com/18 ...

  7. Java并发编程:Lock

    原文出处: 海子 在上一篇文章中我们讲到了如何使用关键字synchronized来实现同步访问.本文我们继续来探讨这个问题,从Java 5之后,在java.util.concurrent.locks包 ...

  8. Java并发编程:Lock(上)

    在上一篇文章中我们讲到了如何使用关键字synchronized来实现同步访问.本文我们继续来探讨这个问题,从Java 5之后,在java.util.concurrent.locks包下提供了另外一种方 ...

  9. [转载] Java并发编程:Lock

    转载自http://www.cnblogs.com/dolphin0520/p/3923167.html 以下是本文目录大纲: 一.synchronized的缺陷 二.java.util.concur ...

  10. Java并发编程:Lock(锁)

    一.synchronized的缺陷 synchronized是java中的一个关键字,也就是说是Java语言内置的特性.那么为什么会出现Lock呢? 在上面一篇文章中,我们了解到如果一个代码块被syn ...

随机推荐

  1. [疑难杂症]解决实际开发中各种问题bug

    我有一个习惯就是遇到问题找到解决方案后收藏网页.后来遇到问题越来越多,收藏就多得有点离谱了.我反思了一下,其实有用的信息就那么点,那我干脆还是做成网页剪报好了. 关于VS的 Problem:未能正确加 ...

  2. 如果你的shiro没学明白,那么应该看看这篇文章,将shiro整合进springboot

    最近在做项目的时候需要用到shiro做认证和授权来管理资源 在网上看了很多文章,发现大多数都是把官方文档的简介摘抄一段,然后就开始贴代码,告诉你怎么怎么做,怎么怎么做 相信很多小伙伴即使是跟着那些示例 ...

  3. MVC,MVP 和 MVVM 的图示(转)

    作者: 阮一峰 日期: 2015年2月 1日 转自:http://www.ruanyifeng.com/blog/2015/02/mvcmvp_mvvm.html 复杂的软件必须有清晰合理的架构,否则 ...

  4. PL/SQL Developer 如何记住密码

    前言:使用时总结一下. 问题: 登录的时候不想每次都输入密码,能记住最好了. 解决方案: 1.点击配置->首选项 2.选择登录历史,勾上带口令存储,然后应用,确定即可.

  5. vue + element ui 阻止表单输入框回车刷新页面

    问题 在 vue+element ui 中只有一个输入框(el-input)的情况下,回车会提交表单. 解决方案 在 el-form 上加上 @submit.native.prevent 这个则会阻止 ...

  6. HDU2612(KB1-N)

    Find a way Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

  7. css画一个提示框

    用css画一个如下图的提示框: 代码如下: <!DOCTYPE html> <html lang="en"> <head> <meta c ...

  8. html中内联元素和块元素的区别、用法以及联系

    昨天用asp.net的BulletedList做一个导航栏,最终该控件形成的html代码是ul列表和a超链接,具体代码如下: <ul id="BulletedList1" s ...

  9. 简单的PHP的任务队列

    文章太长,不作过多介绍,反正,文章的头部就说明了大概的意思...原文如下:写了一个简单的队列任务处理.多进程任务,异步任务可能会用到这个(主要是命令行应用)比如,任务的某个一个环节速度十分不稳定,可能 ...

  10. JS全局变量VAR和THIS--在函数内部,加var是局部变量,不加是全局变量

    JS全局变量VAR和THIS 2011-05-23 21:43 很多人都觉得在JavaScript声明一个变量,加var和不加var没有什么区别,实际上是一个错误的观点,如果在函数外面,也就是说在wi ...