Android ReentrantLock
synchronized原语和ReentrantLock在一般情况下没有什么区别,但是在非常复杂的同步应用中,请考虑使用ReentrantLock,特别是遇到下面2种需求的时候。
1.某个线程在等待一个锁的控制权的这段时间需要中断
2.需要分开处理一些wait-notify,ReentrantLock里面的Condition应用,能够控制notify哪个线程
3.具有公平锁功能,每个到来的线程都将排队等候
下面细细道来……
先说第一种情况,ReentrantLock的lock机制有2种,忽略中断锁和响应中断锁,这给我们带来了很大的灵活性。比如:如果A、B2个线程去竞争锁,A线程得到了锁,B线程等待,但是A线程这个时候实在有太多事情要处理,就是一直不返回,B线程可能就会等不及了,想中断自己,不再等待这个锁了,转而处理其他事情。这个时候ReentrantLock就提供了2种机制,第一,B线程中断自己(或者别的线程中断它),但是ReentrantLock不去响应,继续让B线程等待,你再怎么中断,我全当耳边风(synchronized原语就是如此);第二,B线程中断自己(或者别的线程中断它),ReentrantLock处理了这个中断,并且不再等待这个锁的到来,完全放弃。(如果你没有了解java的中断机制,请参考下相关资料,再回头看这篇文章,80%的人根本没有真正理解什么是java的中断,呵呵)
这里来做个试验,首先搞一个Buffer类,它有读操作和写操作,为了不读到脏数据,写和读都需要加锁,我们先用synchronized原语来加锁,如下:
package cn.vicky.chapt10; /**
*
* @author Vicky.H
*/
public class Buffer { private Object lock; public Buffer() {
lock = this;
} public void write() {
synchronized (lock) {
long startTime = System.currentTimeMillis();
System.out.println("开始往这个buff写入数据…");
for (;;)// 模拟要处理很长时间
{
if (System.currentTimeMillis()
- startTime > Integer.MAX_VALUE) {
break;
}
}
System.out.println("终于写完了");
}
} public void read() {
synchronized (lock) {
System.out.println("从这个buff读数据");
}
} public static void main(String[] args) {
Buffer buff = new Buffer(); final Writer writer = new Writer(buff);
final Reader reader = new Reader(buff); writer.start();
reader.start(); new Thread(new Runnable() { @Override
public void run() {
long start = System.currentTimeMillis();
for (;;) {
//等5秒钟去中断读
if (System.currentTimeMillis()
- start > ) {
System.out.println("不等了,尝试中断");
reader.interrupt();
break;
} } }
}).start();
// 我们期待“读”这个线程能退出等待锁,可是事与愿违,一旦读这个线程发现自己得不到锁,
// 就一直开始等待了,就算它等死,也得不到锁,因为写线程要21亿秒才能完成 T_T ,即使我们中断它,
// 它都不来响应下,看来真的要等死了。这个时候,ReentrantLock给了一种机制让我们来响应中断,
// 让“读”能伸能屈,勇敢放弃对这个锁的等待。我们来改写Buffer这个类,就叫BufferInterruptibly吧,可中断缓存。
}
} class Writer extends Thread { private Buffer buff; public Writer(Buffer buff) {
this.buff = buff;
} @Override
public void run() {
buff.write();
}
} class Reader extends Thread { private Buffer buff; public Reader(Buffer buff) {
this.buff = buff;
} @Override
public void run() { buff.read();//这里估计会一直阻塞 System.out.println("读结束"); }
}
package cn.vicky.chapt10; import java.util.concurrent.locks.ReentrantLock; /**
*
* @author Vicky.H
*/
public class BufferInterruptibly { 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[]) {
BufferInterruptibly buff = new BufferInterruptibly(); 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 > ) {
System.out.println("不等了,尝试中断");
reader.interrupt();
break;
}
}
}
}).start(); }
} class Reader2 extends Thread { private BufferInterruptibly buff; public Reader2(BufferInterruptibly 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 BufferInterruptibly buff; public Writer2(BufferInterruptibly buff) {
this.buff = buff;
} @Override
public void run() {
buff.write();
} }
2个程序,运行结果:
run:
开始往这个buff写入数据…
不等了,尝试中断
run:
开始往这个buff写入数据…
不等了,尝试中断
我不读了
读结束
ReentrantLock是一个互斥的同步器,其实现了接口Lock
一个重要Example:
package tags;
import java.util.Calendar;
public class TestLock {
private ReentrantLock lock = null;
public int data = ; // 用于线程同步访问的共享数据
public TestLock() {
lock = new ReentrantLock(); // 创建一个自由竞争的可重入锁
}
public ReentrantLock getLock() {
return lock;
}
public void testReentry() {
lock.lock();
Calendar now = Calendar.getInstance();
System.out.println(now.getTime() + " " + Thread.currentThread() + " get lock.");
}
public static void main(String[] args) {
TestLock tester = new TestLock();
//1、测试可重入
tester.testReentry();
tester.testReentry(); // 能执行到这里而不阻塞,表示锁可重入
tester.testReentry(); // 再次重入
// 释放重入测试的锁,要按重入的数量解锁,否则其他线程无法获取该锁。
tester.getLock().unlock();
tester.getLock().unlock();
tester.getLock().unlock();
//2、测试互斥
// 启动3个线程测试在锁保护下的共享数据data的访问
new Thread(new workerThread(tester)).start();
new Thread(new workerThread(tester)).start();
new Thread(new workerThread(tester)).start();
}
// 线程调用的方法
public void testRun() throws Exception {
lock.lock();
Calendar now = Calendar.getInstance();
try {
// 获取锁后显示 当前时间 当前调用线程 共享数据的值(并使共享数据 + 1)
System.out.println(now.getTime() + " " + Thread.currentThread()+ " accesses the data " + data++);
Thread.sleep();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
// 工作线程,调用TestServer.testRun
class workerThread implements Runnable {
private TestLock tester = null;
public workerThread(TestLock testLock) {
this.tester = testLock;
}
public void run() {
try {
tester.testRun();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Android ReentrantLock的更多相关文章
- Android进阶——多线程系列之wait、notify、sleep、join、yield、synchronized关键字、ReentrantLock锁
多线程一直是初学者最困惑的地方,每次看到一篇文章,觉得很有难度,就马上叉掉,不看了,我以前也是这样过来的.后来,我发现这样的态度不行,知难而退,永远进步不了.于是,我狠下心来看完别人的博客,尽管很难但 ...
- Android线程管理之Thread使用总结
前言 最近在一直准备总结一下Android上的线程管理,今天先来总结一下Thread使用. 线程管理相关文章地址: Android线程管理之Thread使用总结 Android线程管理之Executo ...
- Android 源码解析之AsyncTask
AsyncTask相信大家都不陌生,它是为了简化异步请求.更新UI操作而诞生的.使用它不仅可以完成我们的网络耗时操作,而且还可以在完成耗时操作后直接的更新我们所需要的UI组件.这使得它在android ...
- android ANR产生原因和解决办法【转】
ANR (Application Not Responding) ANR定义:在Android上,如果你的应用程序有一段时间响应不够灵敏,系统会向用户显示一个对话框,这个对话框称作应用程序无响应(AN ...
- 如何分析解决Android ANR
来自: http://blog.csdn.net/tjy1985/article/details/6777346 http://blog.csdn.net/tjy1985/article/detail ...
- 【Android】[转] ANR的分析和问题处理
一:什么是ANR ANR:Application Not Responding,即应用无响应 二:ANR的类型 ANR一般有三种类型: 1. KeyDispatchTimeout(5 seconds) ...
- Android 开源框架Universal-Image-Loader完全解析(三)---源代码解读
转载请注明本文出自xiaanming的博客(http://blog.csdn.net/xiaanming/article/details/39057201),请尊重他人的辛勤劳动成果,谢谢! 本篇文章 ...
- Android复习资料
转载:http://blog.csdn.net/huachao1001/article/details/53156582 在10月份开始就没有再参与校招了,面试过程真的很累,有时现场等面试一等就是几个 ...
- Android ANR分析(2)
转自:http://blog.csdn.net/ruingman/article/details/53118202 定义 主线程在特定的时间内没有做完特定的事情 常见的场景 A.input事件超过 ...
随机推荐
- Qt之模型/视图(自己定义button)
简述 衍伸前面的章节,我们对QTableView实现了数据显示.自己定义排序.显示复选框.进度条等功能的实现.本节主要针对自己定义button进行解说.这节过后,也希望大家对自己定义有更深入的了解.在 ...
- LINUX设备驱动程序笔记(三)字符设备驱动程序
<一>.主设备号和次设备号 对字符设备的訪问时通过文件系统内的设备名称进行的.那些设备名称简单称之为文件系统树的节点,它们通常位于/dev文件夹. 字符设备驱动程 ...
- Google Web Toolkit(GWT) 在windows下环境搭建
1.什么是GWT? Google Web Toolkit(简称GWT,读作/ˈɡwɪt/),是一个前端使用JavaScript,后端使用Java的AJAX framework,以Apache许可证2. ...
- 5.decltype类型拷贝
#include <iostream> using namespace std; template <class T> void show(T *p) { //初始化 decl ...
- 1. vue环境搭建和配置
const 相对于 var # 全局安装 vue-cli install可以简写成i 1.$ npm install --global vue-cli # 创建一个基于 webpack 模板的新项 ...
- LaTeX indicator function(指示函数)(\mathbb {1} 不起作用)
问题说明: \mathbb字符的空心化显示仅对字符有效,对数字无效. 解决方法: 使用 bbm 包 \documentclass{article} \usepackage{bbm} \begin{do ...
- ES6的学习之路(基础知识总结)
1. 变量声明 1).let 1)使用let定义的变量不会进行"变量提升" console.log(a);//Uncaught ReferenceError: a is not d ...
- cocos2D(一)----第一个cocos2D程序
简单介绍 我们这个专题要学习的是一款iOS平台的2D游戏引擎cocos2d.严格来说叫做cocos2d-iphone,由于cocos2d有非常多个版本号.我们学习的是iphone版本号的.既然是个游戏 ...
- maven 配置Project Facets时further configuration available不出来问题
如果下边的 further configuration available不出来 把Dynamic web module 去掉勾选,应用与项目,然后再点开项目的properties,再选中Dynami ...
- UVA 11039 - Building designing 水题哇~
水题一题,按绝对值排序后扫描一片数组(判断是否异号,我是直接相乘注意中间值越界)即可. 感觉是让我练习sort自定义比较函数的. #include<cstdio> #include< ...