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. cyk追楠神系列一(SDUT3703)

    cyk追楠神系列一 Time Limit: 1000 ms Memory Limit: 65536 KiB Submit Statistic Problem Description 众所周知,cyk ...

  2. tarjan缩点——在农场万圣节Trick or Treat on the Farm

    一个房间能到另一个房间,有向图,奶牛从自己编号(1到n)的点出发,如果回到以前到过的点就停止,问每头奶牛可以经过几个点: 情况分两种, 一,奶牛在环上,能走的是环的大小,二,一条链连接一个环,大小是链 ...

  3. 前端逼死强迫症之css续集

    上节内容回顾 如果点击图片调转到连接,a标签下套img标签,在IE有的版本中,会有蓝色边框. 因为a标签默认字体颜色就是蓝色,img标签继承了父级标签,而IE浏览器默认给边框加了宽度.解决: < ...

  4. 转义字符\'和\"的使用示例

    /* 转义字符\'和\"的使用示例 */ #include <stdio.h> int main(void) { printf("关于字符串常量和字符常量.\n&quo ...

  5. 关于Sign in with Apple 后台验证的一些记录

    2019年10月9号  IOS端新增Sign in with Apple IOS真是世界上最垃圾的语言,没有之一,苹果是世界上最垃圾的公司,没有之一 关于Sign in with Apple 苹果官方 ...

  6. CF1200A

    CF1200A 解法: 给出长度为n的字符串,字符串由'L'.'R'以及数字0~9组成.旅馆有10间房子,L代表客人从左边入住,R代表客人从右边入住,数字则表示第i间房子客人退房了.问经过这n次操作后 ...

  7. Qtcreator中printf()/fprintf()不显示问题处理方法

    此处只介绍解决办法,有兴趣的朋友可以分析原因. [问题] 使用Qtcreator开发项目中,printf()的诊断信息,在“应用程序输出”窗口不显示. [解决方法] 1.printf()不显示解决示例 ...

  8. guava常用集合交集,差集,并集,补集操作

    <!-- https://mvnrepository.com/artifact/com.google.guava/guava --> <dependency> <grou ...

  9. arcpy.UpdateCursor和arcpy.da.UpdateCursor计算面积时间的比较

    arcpy.UpdateCursor ####################### import arcpy from arcpy import env import os import sys f ...

  10. vagrant box镜像百度下载地址

    1.centos7 链接:https://pan.baidu.com/s/1JuIUo4HL0lm1EtUKaoMpaA提取码:w9a8 2.vagrant-ubuntu-server-16.04-x ...