在前面我们在解决线程同步问题的时候使用了synchronized关键字,今天我们来看看Java 5.0以后提供的线程锁Lock.

Lock接口的实现类提供了比使用synchronized关键字更加灵活和广泛的锁定对象操作,而且是以面向对象的方式进行对象加锁。

		@Override
public void run() {
while(true){
Lock lock = new ReentrantLock();
try {
lock.lock();
Thread.sleep(new Random().nextInt(3000));
String data = readData();
System.out.print("读取数据: " + data);
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
lock.unlock();
}
}
}

读写锁:分为读锁和写锁,多个读锁不互斥,读锁与写锁互斥,写锁与写锁互斥,这是由JVM控制的。

import java.util.Random;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock; public class ReadWriteLockTest {
static ReadWriteLock rwl = new ReentrantReadWriteLock(); private static String data = null;
public static void main(String[] args) {
Runnable runnable1 = new MyRunnable1();
Runnable runnable2 = new MyRunnable2();
for(int i=0; i<3; i++){
new Thread(runnable1).start();
new Thread(runnable2).start();
}
} static class MyRunnable1 implements Runnable{ @Override
public void run() {
writeData("" + new Random().nextInt(100));
}
} static class MyRunnable2 implements Runnable{ @Override
public void run() {
readData();
}
} private static void writeData(String var){
rwl.writeLock().lock();
try {
System.out.println(Thread.currentThread().getName() + " 准备写");
Thread.sleep(new Random().nextInt(3000));
data = var;
System.out.println(Thread.currentThread().getName() + " 写完毕");
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
rwl.writeLock().unlock();
} } private static void readData(){
rwl.readLock().lock(); //用读锁锁住
try {
System.out.println(Thread.currentThread().getName() + " 准备读");
Thread.sleep(new Random().nextInt(3000));
System.out.println(Thread.currentThread().getName() + " 读完毕");
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
rwl.readLock().unlock();
}
}
}

用过Hibernate框架的朋友可能知道,Hibernate查询数据库有缓存机制,如果某个数据在内存中存在则可以并发的去读取,如果缓存中没有数据则需要互斥的去从数据库取数据。

import java.util.HashMap;
import java.util.Map;
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 ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
/**
* 实现多个并发读,互斥的写
* @param key
* @return
*/
public Object getData(String key){
rwl.readLock().lock();
Object value = null;
try{
value = cache.get(key);
if(value == null){
rwl.readLock().unlock(); //释放读锁
rwl.writeLock().lock(); //添加写锁
try{
if(value == null){ //放置其他线程加载数据
value = "去数据库查询"; //这里模拟从数据库查询
if(value == null){
//TODO 抛出异常
}
}
}finally{
rwl.writeLock().unlock();
}
rwl.readLock().lock(); //锁还给读线程
}
}finally{
rwl.readLock().unlock();
}
return value;
}
}

上面获取数据的大概过程如下:

1、获取读锁,读取数据

2、如果有数据则直接返回,并释放读锁让其他线程读。

3、如果内存中没有数据则从数据库写入内存,释放读锁并添加写锁(这样写入数据就可以达到可以互斥)

4、读入内存后释放写锁并还回读锁(和后面的unlock()对应)

5、如果在添加写锁的时候同时有多个线程,则只能有其中一个线程抢到锁,等拥有锁的线程释放写锁后,其他线程就会抢到写锁,但是此时数据已经写入内存,则需要判断内存数据是否为null如果不为null则直接释放写锁。

Android多线程研究(9)——线程锁Lock的更多相关文章

  1. 孤荷凌寒自学python第三十九天python 的线程锁Lock

    孤荷凌寒自学python第三十九天python的线程锁Lock (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) 当多个线程同时操作一个文件等需要同时操作某一对象的情况发生时,很有可能发生冲突, ...

  2. C# 关于线程锁lock的使用方法

    C# 关于线程锁lock的使用方法 原创 2016年09月02日 10:07:05 标签: c# / 线程 / 锁 / lock 11937 在多线程编程中,可能会有许多线程并发的执行一段代码(代码块 ...

  3. Android多线程研究(6)——多线程之间数据隔离

    在上一篇<Android多线程研究(5)--线程之间共享数据>中对线程之间的数据共享进行了学习和研究,这一篇我们来看看怎样解决多个线程之间的数据隔离问题,什么是数据隔离呢?比方说我们如今开 ...

  4. python 多线程中的同步锁 Lock Rlock Semaphore Event Conditio

    摘要:在使用多线程的应用下,如何保证线程安全,以及线程之间的同步,或者访问共享变量等问题是十分棘手的问题,也是使用多线程下面临的问题,如果处理不好,会带来较严重的后果,使用python多线程中提供Lo ...

  5. JAVA多线程提高八:线程锁技术

    前面我们讲到了synchronized:那么这节就来将lock的功效. 一.locks相关类 锁相关的类都在包java.util.concurrent.locks下,有以下类和接口: |---Abst ...

  6. JAVA多线程学习十一-线程锁技术

    前面我们讲到了synchronized:那么这节就来将lock的功效. 一.locks相关类 锁相关的类都在包java.util.concurrent.locks下,有以下类和接口: |---Abst ...

  7. 并发库应用之四 & 线程锁Lock应用

    Java5的线程并发库中,提供了相应的线程锁接口Lock来帮助我们同步处理.Lock比传统线程模型中的synchronized更加面向对象,锁本身也是一个对象,两个线程执行的代码要实现同步互斥效果,就 ...

  8. Android多线程研究(1)——线程基础及源代码剖析

    从今天起我们来看一下Android中的多线程的知识,Android入门easy,可是要完毕一个完好的产品却不easy,让我们从线程開始一步步深入Android内部. 一.线程基础回想 package ...

  9. Android多线程研究(1)——线程基础及源码剖析

    从今天起我们来看一下Android中的多线程的知识,Android入门容易,但是要完成一个完善的产品却不容易,让我们从线程开始一步步深入Android内部. 一.线程基础回顾 package com. ...

随机推荐

  1. 源代码编译安装CloudStack 4.2

    基于CentOS 6.4安装CloudStack 环境配置 # yum -y update # yum -y upgrade 安装NTP,jdk 1.7, tomcat 6, mysql,git等服务 ...

  2. 測试CPU支持指令集AVX,AVX2,SSE情况的代码【VS2010调试通过】

    完整代码例如以下所看到的 http://download.csdn.net/detail/vbskj/7723827 本人的測试结果 watermark/2/text/aHR0cDovL2Jsb2cu ...

  3. actionBar-shareIcon 分享按钮的修改

    今天为了修改图库的分享按钮,进行了很多的尝试 1.寻找到了xml文件,如下 <?xml version="1.0" encoding="utf-8"?&g ...

  4. Cookie应用--显示看过的商品

    package cn.itcast; import java.io.IOException; import java.io.PrintWriter; import java.util.LinkedHa ...

  5. IIS6下AD域设置

    简介:IIS6下AD域设置 IIS6下AD域设置 http://files.cnblogs.com/files/KingUp/AD%E5%9F%9F%E8%AE%BE%E7%BD%AE.rar

  6. Code froces 831 A. Unimodal Array

    A. Unimodal Array time limit per test 1 second memory limit per test 256 megabytes input standard in ...

  7. POJ 1082 Calendar Game

    Adam and Eve enter this year's ACM International Collegiate Programming Contest. Last night, they pl ...

  8. Jmeter使用_处理响应结果显示乱码

    1. 添加BeanShell PostProcessor 输入prev.setDataEncoding("utf-8"); 目的是修改响应数据编码格式为utf-8,保存

  9. 将二级目录下的文件合并成一个文件的Python小脚本

    这个小程序的目的是将二级目录下的文件全部合并成一个文件(其实几级目录都可以,只要做少许改动) #coding:utf8 import sys, os def process(path): new_fi ...

  10. 理解宏的使用 extern

    如何定义一个全局变量在一个文件中,然后在其它文件中调用就行,而不需要多次extern外部声明. 由于之前的公司的程序中全局的变量使用得很多,在多个.C文件中会调用,不这样处理做的话就会多处进行exte ...