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 ...
随机推荐
- 《DSP using MATLAB》示例Example 8.28
%% ------------------------------------------------------------------------ %% Output Info about thi ...
- python 客户端点对点通信小案例
点对点通讯分为客户端和服务器,多个客户端通过服务器进行信息的交流 服务器端代码 service端 #!/usr/bin/env python # -*- coding:utf-8 -*- impor ...
- SEO方案
前端需要注意哪些SEO 合理的title.description.keywords:搜索对着三项的权重逐个减小,title值强调重点即可,重要关键词出现不要超过2次,而且要靠前,不同页面title要有 ...
- (转)Linux查看CPU,硬盘,内存的大小
分类: linux(21) 在Linux的桌面版本中,查看这些东西的确很方便,有图形化的工具可以使用.但是在Linux服务器版上,或者远程ssh连接的时候,就没有图形化的界面可以操作了.此 ...
- MEF学习总结(4)---Container层
通过AttributeedModelPrograming,我们可以声明暴露组件,依赖组件,发现组件,但是所有这些需要有一个触发点.即需要把所有这些组合在一起来协同工作,最终实现依赖注入.这就是Cont ...
- Python笔试面试题_牛客(待完善)
中文,免费,零起点,完整示例,基于最新的Python 3版本.https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42 ...
- SharePoint2013工作流workflow manager配置
SharePoint2013版本的工作流较sharepoint 2010变化较大,将工作流部分从sharepoint中分离出来为单独的服务,通过与sharepoint关联使用. SharePoint2 ...
- 封装与继承(PHP学习)
什么是封装? 答:封装时不知道内部构造,对外部只展现功能的这种行为.例如:收音机,你不知道收音机内部的构造,但是你知道收音机是能用来听广播的. 在PHP中,封装是,不对外公布,属性和方法,这些属性和方 ...
- 打包python文件,让文件程序化
通过对源文件打包,Python程序可以在没有安装 Python的环境中运行,也可以作为一个独立文件方便传递和管理. 现在网上主流的打包方式有两种py2exe或者pyinstaller两款多平台的Pyt ...
- [转载]嵌入式linux启动时运行的inittab文件
源地址:https://www.cnblogs.com/yfz0/p/5853826.html 嵌入式系统下的linux启动配置文件,不同与普通的PC linux启动配置,启动相关文件与文件的内容也要 ...