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();
}
}
}

读写文件

Read Thread
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的事儿的更多相关文章

  1. ThreadLocal 那点事儿

    原文出处: 黄勇 ThreadLocal,直译为“线程本地”或“本地线程”,如果你真的这么认为,那就错了!其实,它就是一个容器,用于存放线程的局部变量,我认为应该叫做 ThreadLocalVaria ...

  2. ThreadLocal 那点事儿(续集)

    本篇是<ThreadLocal 那点事儿>的续集,如果您没看上一篇,就就有点亏了.如果您错过了这一篇,那亏得就更大了. 还是保持我一贯的 Style,用一个 Demo 来说话吧.用户提出一 ...

  3. ThreadLocal使用场景案例

    本篇是<ThreadLocal 那点事儿>的续集,如果您没看上一篇,就就有点亏了.如果您错过了这一篇,那亏得就更大了. 还是保持我一贯的 Style,用一个 Demo 来说话吧.用户提出一 ...

  4. 架构探险——第二章(为web应用添加业务功能)

    第二章不使用框架完成了自己的Web应用. 重点: 服务层的完善优化过程,思路 在看这一段的时候引起了无数次的共鸣.相信大家在开始接触Java Web的时候,都做过类似的封装和优化. 第一版 在Serv ...

  5. 关于 SimpleDateFormat 的非线程安全问题及其解决方案

    一直以来都是直接用SimpleDateFormat开发的,没想着考虑线程安全的问题,特记录下来(摘抄的): 1.问题: 先来看一段可能引起错误的代码: package test.date; impor ...

  6. Java_基础_02_ThreadLocal

    二.参考资料 1.ThreadLocal 那点事儿 2.彻底理解ThreadLocal

  7. Java并发编程:synchronized、Lock、ReentrantLock以及ReadWriteLock的那些事儿

    目录 前言 synchronized用法 修饰方法 修饰实例方法 修饰静态方法 同步代码块 引出Lock Lock用法 子类:ReentrantLock 读写分离锁:ReadWriteLock Loc ...

  8. Synchronized、lock、volatile、ThreadLocal、原子性总结、Condition

    http://blog.csdn.net/sinat_29621543/article/details/78065062

  9. 多线程同步工具——Lock

    本文原创,转载请注明出处. 参考文章: <"JUC锁"03之 公平锁(一)> <"JUC锁"03之 公平锁(二)> 锁分独占锁与共享锁, ...

随机推荐

  1. java试题复盘——11月25日

    上: 11.下列表述错误的是?(D) A.int是基本类型,直接存数值,Integer是对象,用一个引用指向这个对象. B.在子类构造方法中使用super()显示调用父类的构造方法,super()必须 ...

  2. Ocelot 网关 和 consul 服务发现

    服务发现 Consul 一.安装和启动 下载 [Consul](https://www.consul.io/downloads.html) 下载完成后,解压,只有一个consul.exe,把目录添加到 ...

  3. Tensorflow使用训练好的模型进行测试,发现计算速度越来越慢

    实验时要对多个NN模型进行对比,依次加载直到第8个模型时,发现运行速度明显变慢而且电脑开始卡顿,查看内存占用90+%. 原因:使用过的NN模型还会保存在内存,继续加载一方面使新模型加载特别特别慢,另一 ...

  4. Flutter移动电商实战 --(31)列表页_列表切换交互制作

    点击左侧的大类右边的小类也跟着变化 新建provide 要改变哪里就建哪里的provide,我们现在要改变的是右边的商品列表的数组. category_goods_list.dart 这样我们的pro ...

  5. kotlin set get

    1.类定义属性 默认是public的. 2.var 一个变量,也是就是属性,自动生成set get方法. 3.val 常量,没有set方法. 4. 延迟初始化属性        对于非空类型的属性是必 ...

  6. mysql安装到启动遇见的问题

    一.有时候安装mysql后使用mysql命令时报错 Can't connect to MySQL server on localhost (10061),或者用net start mysql 时报服务 ...

  7. python 语法糖是什么意思

    语法糖指那些没有给计算机语言添加新功能,而只是对人类来说更“甜蜜”的语法.语法糖往往给程序员提供了更实用的编码方式,有益于更好的编码风格,更易读.不过其并没有给语言添加什么新东西.

  8. 002-log-log4j

    一.概述 Log4j是Apache的一个开放源代码项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台.文件.GUI组件.甚至是套接口服务器.NT的事件记录器.UNIX Syslog守护 ...

  9. 阶段5 3.微服务项目【学成在线】_day04 页面静态化_12-页面静态化-页面静态化流程

    需要知道数据结构,然后去做模板标签.首先需要获取页面的数据模型.下面的每一条记录都代表一个页面. 比如这个轮播图.就需要提前给这个轮播图编写一个模板 有很多的页面如果知道每个页面的dataUrl.例如 ...

  10. 硬核讲解 Jetpack 之 LifeCycle 源码篇

    前一篇 硬核讲解 Jetpack 之 LifeCycle 使用篇 主要介绍了 LifeCycle 存在的意义,基本和进阶的使用方法.今天话不多说,直接开始撸源码. 本文基于我手里的 android_9 ...