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 方法或代码块。

最新文章

  1. 纸箱堆叠 bzoj 2253
  2. Java暗箱操作之自动装箱与拆箱
  3. Google Maps API V3 之 图层
  4. Provisioning Services 7.6 入门到精通系列之二:基础架构环境
  5. web前端基础篇⑨
  6. python(九)re模块
  7. CSS3制作苹果风格键盘
  8. Flash中的文本应用
  9. ActiveMQ发布订阅模式(转)
  10. appium使用真机做安卓移动端自动化测试
  11. C# 视频多人脸识别
  12. 你不可不知的Java引用类型之——SoftReference源码详解
  13. dubbo的本地存根(Stub)
  14. Tensorflow serving with Kubernetes
  15. Python开发【项目】:学员管理系统(mysql)
  16. form 表单中 button 按钮用 return false 阻止默认刷新踩过的一个小坑
  17. PL/SQL如何设置当前格局确保每次打开都给关闭前一样
  18. 关于源码输出,浏览器不解析Html标签
  19. 嵌入式开发之hi3519---spi nor flash启动
  20. CAN/J1850/

热门文章

  1. jieba中文处理
  2. 在Android中使用OpenGL ES开发第(四)节:相机预览
  3. Cash Machine (POJ 1276)(多重背包——二进制优化)
  4. 超大地图MMORPG的场景管理
  5. 菜单栏伸缩(附jquery-1.12.1.js)
  6. ZOJ 2592 Think Positive ——(xjbg)
  7. Hdu5178
  8. powderdesinger显示中英文表名
  9. Mac Mysql 5.6.4修改初始化密码
  10. CentOS7重启后resolv.conf被重置的解决方案