Java核心知识点 --- 线程中如何创建锁和使用锁 Lock , 设计一个缓存系统
理论知识很枯燥,但这些都是基本功,学完可能会忘,但等用的时候,会发觉之前的学习是非常有意义的,学习线程就是这样子的.
1.如何创建锁?
Lock lock = new ReentrantLock();
2.如何使用锁?
可以参看Lock文档,其使用格式如下:

class X {
private final ReentrantLock lock = new ReentrantLock();
// ...
public void m() {
lock.lock(); // block until condition holds
try {
// ... method body
} finally {
lock.unlock()
}
}
}

在要用的方法前加上锁,比如写操作,然后在finally中将锁打开.
这里,将前文java核心知识点学习----多线程并发之线程同步中的代码改用Lock实现数据同步,改写代码如下:

package com.amos.concurrent; import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; /**
* @ClassName: LockTest
* @Description: Lock学习
* @author: amosli
* @email:hi_amos@outlook.com
* @date Apr 22, 2014 1:48:36 AM
*/
public class LockTest {
public static void main(String[] args) {
new LockTest().init();
} private void init() {
final OutPuter outPuter = new OutPuter();
// 新建一个线程
new Thread(new Runnable() {
public void run() {
while (true) {
// 休息10ms
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
outPuter.output("hi_amos");// 输出
}
}
}).start();
new Thread(new Runnable() {
public void run() {
while (true) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
outPuter.output("amosli");
}
}
}).start();
} static class OutPuter {
// 方式1:使用synchronized关键字
// public synchronized void output(String name) {
// int length = name.length();
// for (int i = 0; i < length; i++) {
// System.out.print(name.charAt(i));
// }
// System.out.println();
// } // 方式2:使用Lock锁
Lock lock = new ReentrantLock(); public void output(String name) {
lock.lock();// 加锁
int length = name.length();
// 输出name,逐个字节读取,并输出
try {
for (int i = 0; i < length; i++) {
System.out.print(name.charAt(i));
}
System.out.println();
} finally {
lock.unlock();// 解锁
}
}
}
}

3.synchronized关键字与Lock的区别?
1).Lock是Java5中的新特性,更加面向对象.更类似于生活中的锁.
2).Lock锁一般需要手动开启和关闭,而synchronized则不需要.
建议优先使用Lock.
4.注意事项:
1)多个读锁不互斥,读锁与写锁互斥,写锁与写锁互斥.
2)要实现两个线程互斥,那么要将锁加到同一个被访问对象上.
3)如果你的代码修改数据,只能有一个人在写,且不能同时读取,那就上写锁,总之,读的时候用读锁,写的时候用写锁!
5.设计一个缓存系统
什么是缓存系统? 就是看本地是否已经缓存过此数据,如果已经缓存过,那就直接拿来用;如果没有缓存过,那就查询数据库.
下面看代码:

private Map<String, Object> cache = new HashMap<String, Object>();
public synchronized Object getData(String key){
Object object = cache.get(key);
if (object==null) {
object = "1323";//实际是去queryDB();
}
return object;
}

这里其实是一个超级简单的缓存系统,原理就是:第一次访问的时候把值存入到cache中,第二次访问时,先去看cache中是否有值如果有值,那么就直接去取值,而不是从数据库中去取.
为什么要加上synchronized? 这是为了保持数据互斥,访问的时候不相互影响,因为其中有对object进行赋值操作,这是一个写操作,所以最好加上锁.
如何优化?

private ReadWriteLock rwl = new ReentrantReadWriteLock();
public synchronized Object getData(String key){
rwl.readLock();//read lock
Object object = cache.get(key);
try{
if (object==null) {
rwl.readLock().unlock();//释放锁
rwl.writeLock().lock();//对写加锁
try{
object = "1323";//实际是去queryDB();
}finally{
rwl.writeLock().unlock();
}
}
}finally{
rwl.readLock().unlock();
}
return object;
}

上面的代码运用到了刚学到的知识,对所有读和写进行加锁,以保持线程间的互斥,要特别注意的是要在finally中把锁打开,不管程序是否执行成功,因为如果不解锁,那么程序将会产生死锁,关于死锁,将在接下来的文章中介绍.
Java核心知识点 --- 线程中如何创建锁和使用锁 Lock , 设计一个缓存系统的更多相关文章
- Java核心知识点学习----线程中如何创建锁和使用锁 Lock,设计一个缓存系统
理论知识很枯燥,但这些都是基本功,学完可能会忘,但等用的时候,会发觉之前的学习是非常有意义的,学习线程就是这样子的. 1.如何创建锁? Lock lock = new ReentrantLock(); ...
- java核心知识点 --- 线程池ThreadPool
线程池是多线程学习中需要重点掌握的. 系统启动一个新线程的成本是比较高的,因为它涉及与操作系统交互.在这种情形下,使用线程池可以很好的提高性能,尤其是当程序中需要创建大量生存期很短暂的线程时,更应该考 ...
- Java核心知识点学习----使用Condition控制线程通信
一.需求 实现线程间的通信,主线程循环3次后,子线程2循环2次,子线程3循环3次,然后主线程接着循环3次,如此循环3次. 即:A->B->C---A->B->C---A-> ...
- Java核心知识点学习----多线程中的阻塞队列,ArrayBlockingQueue介绍
1.什么是阻塞队列? 所谓队列,遵循的是先进先出原则(FIFO),阻塞队列,即是数据共享时,A在写数据时,B想读同一数据,那么就将发生阻塞了. 看一下线程的四种状态,首先是新创建一个线程,然后,通过s ...
- java核心知识点学习----并发和并行的区别,进程和线程的区别,如何创建线程和线程的四种状态,什么是线程计时器
多线程并发就像是内功,框架都像是外功,内功不足,外功也难得精要. 1.进程和线程的区别 一个程序至少有一个进程,一个进程至少有一个线程. 用工厂来比喻就是,一个工厂可以生产不同种类的产品,操作系统就是 ...
- java核心知识点学习----重点学习线程池ThreadPool
线程池是多线程学习中需要重点掌握的. 系统启动一个新线程的成本是比较高的,因为它涉及与操作系统交互.在这种情形下,使用线程池可以很好的提高性能,尤其是当程序中需要创建大量生存期很短暂的线程时,更应该考 ...
- Java进阶知识点6:并发容器背后的设计理念 - 锁分段、写时复制和弱一致性
一.背景 容器是Java编程中使用频率很高的组件,但Java默认提供的基本容器(ArrayList,HashMap等)均不是线程安全的.当容器和多线程并发编程相遇时,程序员又该何去何从呢? 通常有两种 ...
- Java核心复习——线程池ThreadPoolExecutor源码分析
一.线程池的介绍 线程池一种性能优化的重要手段.优化点在于创建线程和销毁线程会带来资源和时间上的消耗,而且线程池可以对线程进行管理,则可以减少这种损耗. 使用线程池的好处如下: 降低资源的消耗 提高响 ...
- JAVA线程锁-读写锁应用,简单的缓存系统
在JAVA1.5版本以后,JAVA API中提供了ReadWriteLock,此类是一个接口,在它的实现类中ReentrantReadWriteLock中有这样一段代码 class CachedDat ...
随机推荐
- python3 scrapy main运行调式
from scrapy.cmdline import execute import sys import os sys.path.append(os.path.dirname(os.path.absp ...
- 《DSP using MATLAB》示例Example7.6 Type-3 Linear-Phase FIR
代码: h = [-4, 1, -1, -2, 5, 0, -5, 2, 1, -1, 4]; M = length(h); n = 0:M-1; [Hr, w, c, L] = Hr_Type3(h ...
- java基本类型和封装类型区别及应用
1.基本类型只能按值传递,而每个基本类型对应的封装类是按引用传递的. 2.从性能上说java中的基本类型是在堆栈上创建的,而所有的对象类型都是在堆上创建的,(对象的引用在堆栈上创建).比如 Integ ...
- 日志框架--(二)JDK Logging
前言 从jdk1.4起,JDK开始自带一套日志系统.JDK Logger最大的优点就是不需要任何类库的支持,只要有Java的运行环境就可以使用.相对于其他的日志框架,JDK自带的日志可谓是鸡肋,无论易 ...
- saas 系统租户个性化域名&&租户绑定自己域名的解决方案
实际的需求就类似github 的自定义page 1. 个性化域名 github 实现原理就是用户个性化域名使用泛域名解析,这个比较简单,大部分域名提供商都可以解决 具体操作不用赘述 ...
- VS2010单元测试入门实践教程
单元测试的重要性这里我就不多说了,以前大家一直使用NUnit来进行单元测试,其实早在Visual Studio 2005里面,微软就已经集成了一个叫Test的专门测试插件,经过几年的发展,这个工具现在 ...
- (转)JavaMail邮件发送-发送一个文本邮件和一些问题说明
需要下载的JAR包: JavaMail:http://www.oracle.com/technetwork/java/javamail/index.html JAF:http://www.oracle ...
- 2dx 3.0环境配置(mac)
安装ant brew install ant ant默认的目录在 /usr/local/bin mvim ~/.profile,添加 export ANT_ROOT=/usr/local/bin . ...
- librtmp接收flv流中提取h264码流:根据多个资料汇总
rtmpdump可以下载rtmp流并保存成flv文件.如果要对流中的音频或视频单独处理,需要根据flv协议分别提取.简单修改rtmpdump代码,增加相应功能.1 提取音频:rtmpdump程序在Do ...
- git 绑定远程仓方法
第1步:创建SSH Key.在用户主目录下,看看有没有.ssh目录,如果有,再看看这个目录下有没有id_rsa和id_rsa.pub这两个文件,如果已经有了,可直接跳到下一步.如果没有,打开Shell ...