ThreadLocal,Lock的事儿
ThreadLocal作用 防止线程间的干扰
public interface Sequence {
int getNumber();
}
public class ClientThread extends Thread {
private Sequence sequence;
public ClientThread(Sequence sequence) {
this.sequence = sequence;
}
@Override
public void run() {
for (int i = 0; i < 3; i++) {
System.out.println(Thread.currentThread().getName() + " => " + sequence.getNumber());
}
}
}
public class SequenceA implements Sequence {
private static int number = 0;
public int getNumber() {
number = number + 1;
return number;
}
public static void main(String[] args) {
Sequence sequence = new SequenceA();
ClientThread thread1 = new ClientThread(sequence);
ClientThread thread2 = new ClientThread(sequence);
ClientThread thread3 = new ClientThread(sequence);
thread1.start();
thread2.start();
thread3.start();
}
}
Thread-0 => 1
Thread-0 => 2
Thread-0 => 3
Thread-2 => 4
Thread-2 => 5
Thread-2 => 6
Thread-1 => 7
Thread-1 => 8
Thread-1 => 9
线程之间共享了 static 变量
线程干扰
使用ThreadLocal当作容器
public class SequenceB implements Sequence {
private static ThreadLocal<Integer> numberContainer = new ThreadLocal<Integer>() {
@Override
protected Integer initialValue() {
return 0;
}
};
public int getNumber() {
numberContainer.set(numberContainer.get() + 1);
return numberContainer.get();
}
public static void main(String[] args) {
Sequence sequence = new SequenceB();
ClientThread thread1 = new ClientThread(sequence);
ClientThread thread2 = new ClientThread(sequence);
ClientThread thread3 = new ClientThread(sequence);
thread1.start();
thread2.start();
thread3.start();
}
}
这样就不共享了
使用ThreadLocal
ThreadLocal原理
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
private T setInitialValue() {
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
return value;
}
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
就是以当前线程为键创建了map
含有事务时,可以把 Connection 放到了 ThreadLocal 中,将每个线程的connection隔开
Lock 的事儿
遇到一个文件可以多人同时读,但不能同时写
public class Data {
private final char[] buffer;
public Data(int size) {
this.buffer = new char[size];
for (int i = 0; i < size; i++) {
buffer[i] = '*';
}
}
public String read() {
StringBuilder result = new StringBuilder();
for (char c : buffer) {
result.append(c);
}
sleep(100);
return result.toString();
}
public void write(char c) {
for (int i = 0; i < buffer.length; i++) {
buffer[i] = c;
sleep(100);
}
}
private void sleep(long ms) {
try {
Thread.sleep(ms);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
读写文件
public class WriterThread extends Thread {
private final Data data;
private final String str;
private int index = 0;
public WriterThread(Data data, String str) {
this.data = data;
this.str = str;
}
@Override
public void run() {
while (true) {
char c = next();
data.write(c);
}
}
private char next() {
char c = str.charAt(index);
index++;
if (index >= str.length()) {
index = 0;
}
return c;
}
}
Write Thread
资源的访问一定要做到“共享互斥”
public class Data {
...
public synchronized String read() {
...
}
public synchronized void write(char c) {
...
}
...
}
加锁
加锁后性能慢 , 自己创建锁
public class ReadWriteLock {
private int readThreadCounter = 0; // 正在读取的线程数(0个或多个)
private int waitingWriteCounter = 0; // 等待写入的线程数(0个或多个)
private int writeThreadCounter = 0; // 正在写入的线程数(0个或1个)
private boolean writeFlag = true; // 是否对写入优先(默认为是)
// 读取加锁
public synchronized void readLock() throws InterruptedException {
// 若存在正在写入的线程,或当写入优先时存在等待写入的线程,则将当前线程设置为等待状态
while (writeThreadCounter > 0 || (writeFlag && waitingWriteCounter > 0)) {
wait();
}
// 使正在读取的线程数加一
readThreadCounter++;
}
// 读取解锁
public synchronized void readUnlock() {
// 使正在读取的线程数减一
readThreadCounter--;
// 读取结束,对写入优先
writeFlag = true;
// 通知所有处于 wait 状态的线程
notifyAll();
}
// 写入加锁
public synchronized void writeLock() throws InterruptedException {
// 使等待写入的线程数加一
waitingWriteCounter++;
try {
// 若存在正在读取的线程,或存在正在写入的线程,则将当前线程设置为等待状态
while (readThreadCounter > 0 || writeThreadCounter > 0) {
wait();
}
} finally {
// 使等待写入的线程数减一
waitingWriteCounter--;
}
// 使正在写入的线程数加一
writeThreadCounter++;
}
// 写入解锁
public synchronized void writeUnlock() {
// 使正在写入的线程数减一
writeThreadCounter--;
// 写入结束,对读取优先
writeFlag = false;
// 通知所有处于等待状态的线程
notifyAll();
}
}
ReadWriteLock
jdk已经提供了这种锁
public interface Lock {
void lock();
void lockInterruptibly() throws InterruptedException;
boolean tryLock();
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
void unlock();
Condition newCondition();
}
Lock
public class Data {
...
private final ReadWriteLock lock = new ReentrantReadWriteLock(); // 创建读写锁
private final Lock readLock = lock.readLock(); // 获取读锁
private final Lock writeLock = lock.writeLock(); // 获取写锁
...
public String read() throws InterruptedException {
readLock.lock(); // 读取上锁
try {
return doRead(); // 执行读取操作
} finally {
readLock.unlock(); // 读取解锁
}
}
public void write(char c) throws InterruptedException {
writeLock.lock(); // 写入上锁
try {
doWrite(c); // 执行写入操作
} finally {
writeLock.unlock(); // 写入解锁
}
}
...
}
加锁后的操作data
当系统中出现不同的读写线程同时访问某一资源时,需要考虑共享互斥问题,可使用 synchronized 解决次问题。若对性能要求较高的情况下,可考虑使用 ReadWriteLock 接口及其 ReentrantReadWriteLock 实现类,当然,自己实现一个 ReadWriteLock 也是一种解决方案。此外,为了在高并发情况下获取较高的吞吐率,建议使用 Lock 接口及其 ReentrantLock 实现类来替换以前的 synchronized 方法或代码块。
ThreadLocal,Lock的事儿的更多相关文章
- ThreadLocal 那点事儿
原文出处: 黄勇 ThreadLocal,直译为“线程本地”或“本地线程”,如果你真的这么认为,那就错了!其实,它就是一个容器,用于存放线程的局部变量,我认为应该叫做 ThreadLocalVaria ...
- ThreadLocal 那点事儿(续集)
本篇是<ThreadLocal 那点事儿>的续集,如果您没看上一篇,就就有点亏了.如果您错过了这一篇,那亏得就更大了. 还是保持我一贯的 Style,用一个 Demo 来说话吧.用户提出一 ...
- ThreadLocal使用场景案例
本篇是<ThreadLocal 那点事儿>的续集,如果您没看上一篇,就就有点亏了.如果您错过了这一篇,那亏得就更大了. 还是保持我一贯的 Style,用一个 Demo 来说话吧.用户提出一 ...
- 架构探险——第二章(为web应用添加业务功能)
第二章不使用框架完成了自己的Web应用. 重点: 服务层的完善优化过程,思路 在看这一段的时候引起了无数次的共鸣.相信大家在开始接触Java Web的时候,都做过类似的封装和优化. 第一版 在Serv ...
- 关于 SimpleDateFormat 的非线程安全问题及其解决方案
一直以来都是直接用SimpleDateFormat开发的,没想着考虑线程安全的问题,特记录下来(摘抄的): 1.问题: 先来看一段可能引起错误的代码: package test.date; impor ...
- Java_基础_02_ThreadLocal
二.参考资料 1.ThreadLocal 那点事儿 2.彻底理解ThreadLocal
- Java并发编程:synchronized、Lock、ReentrantLock以及ReadWriteLock的那些事儿
目录 前言 synchronized用法 修饰方法 修饰实例方法 修饰静态方法 同步代码块 引出Lock Lock用法 子类:ReentrantLock 读写分离锁:ReadWriteLock Loc ...
- Synchronized、lock、volatile、ThreadLocal、原子性总结、Condition
http://blog.csdn.net/sinat_29621543/article/details/78065062
- 多线程同步工具——Lock
本文原创,转载请注明出处. 参考文章: <"JUC锁"03之 公平锁(一)> <"JUC锁"03之 公平锁(二)> 锁分独占锁与共享锁, ...
随机推荐
- SPOJ GSS1 - Can you answer these queries I(线段树维护GSS)
Can you answer these queries I SPOJ - GSS1 You are given a sequence A[1], A[2], -, A[N] . ( |A[i]| ≤ ...
- Irrlicht引擎剖析一
代码风格: 1.接口以I开头,实现以C开头,保存数据的结构体以S开头 2.函数名以小写字母开头,变量以大字母开头 3.接口的公共函数,其参数大部分给了默认值 4.采用名字空间 名字空间i ...
- 设置tomcat实现跨域
1.tomcat下自带的cors过滤器 修改tomcat路径下conf/web.xml文件 <filter> <filter-name>CorsFilter</filte ...
- 5 款最酷的 Linux 终端模拟器
转载:https://cloud.tencent.com/developer/article/1040344 首先我要推荐的第一个终端是 Xiki. Xiki 是 Craig Muth 的智慧结晶,他 ...
- python 装饰器应用
1 注册回调函数 下面这个示例展示了通过URL的路由来调用相关注册的函数示例: class MyApp(): def __init__(self): self.func_map = {} def re ...
- Python语法 - 推导式
推导式分为列表推导式(list),字典推导式(dict),集合推导式(set)三种 列表推导式(list comprehension)最擅长的方式就是对整个列表分别做相同的操作,并且返回得到一个新的列 ...
- kafka学习汇总系列(一)kafka概述
一.kafka概述 在流式计算中,kafka是用来缓存数据的,storm通过消费kafka的数据进行计算.kafka的初心是,为处理实时数据提供一个统一.高通量.低等待的平台: 1.kafka是一个分 ...
- sed中使用变量及变量中存在特殊字符‘/’处理
sed中使用变量,普通的处理方式无法解析变量 如当前file文件中存在字符串pedis,现将其替换为redis [root@localhost work]# cat file pedis 如下两种替换 ...
- SOCKET原理(转载)
SOCKET原理 一.套接字(socket)概念 套接字(socket)是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元.它是网络通信过程中端点的抽象表示,包含进行网络通信必须的五种信息: ...
- vue2.0中 怎么引用less?
vue2.0中 怎么引用less? 第一步: 安装less依赖, npm install less less-loader --save 第二步: 修改webpack.config.js文件,配置l ...