定义: 通过不共享变量实现线程安全,并规避锁的消耗及相关锁带来的问题
ApplicationThread: 线程持有存储模式的客户端,表示各个应用线程
TSObjectProxy: 用于访问线程特有对象的代理对象
getThreadSpecific: 获取与其所属TSObjectProxy实例相关联的线程特有对象实例
setThreadSpecific: 建立其所属TSObjectProxy实例与执行线程持有对象实例的关联
removeThreadSpecific: 删除其所属TSObjectProxy实例与线程特有对象实例的关联
TSObject: 表示线程持有对象
ThreadSpecificStorage: 线程特有存储,可以理解为一个Map
get: 获取与指定TSObjectProxy实例关联的TSObject实例
set: 设置指定TSObjectProxy实例与指定TSObject实例的关联关系
想要在并发环境下生成随机数,此时可以考虑SecureRandom类来生成随机数,但是从源码中我们可以了解,SecureRandom#nextInt()方法是继承自线程安全类java.util.Random,而Random类随机数生成的具体实现(见如下代码:方法java.util.Random#next())使用了CAS机制,导致在并发环境下性能极其糟糕。同时,还有一个问题是如果使用synchronized方法会导致除生成随机数的线程在运行,其它线程都必须等待,性能也不甚理想。有鉴于其,可以考虑不在多个线程间共享SecureRandom实例,采用线程特有存储模式来解决。也就是说用ThreadLocal类实现生成随机数的线程每个线程有且仅有一个SecureRandom实例,从而避免大量的上下文切换。
protected int next(int bits) {
long oldseed, nextseed;
AtomicLong seed = this.seed;
do {
oldseed = seed.get();
nextseed = (oldseed * multiplier + addend) & mask;
} while (!seed.compareAndSet(oldseed, nextseed));
return (int)(nextseed >>> (48 - bits));
}
下列代码主要是为了展示多线程编程模式-线程特有存储模式,在Java1.7中,并发领域的权威大神Doug Lea先生引入类java.util.concurrent.ThreadLocalRandom,就是适用于并发场景下生成随机数的类,可以直接拿来使用。如果对于java.util.Random, java.util.concurrent.ThreadLocalRandom及ThreadLocal<Random>三者之间性能的差异有多少,可以阅读推荐文章多线程环境下生成随机数
package com.bruce.threadSpecificStorage;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
/**
* @Author: Bruce
* @Date: 2019/6/4 12:27
* @Version 1.0
*/
public class ThreadSpecificSecureRandom {
public static final ThreadSpecificSecureRandom INSTANCE =
new ThreadSpecificSecureRandom();
private static final ThreadLocal<SecureRandom> SECURE_RANDOM = new ThreadLocal<SecureRandom>() {
@Override
protected SecureRandom initialValue() {
SecureRandom srnd;
try {
srnd = SecureRandom.getInstance("SHA1PRNG");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
srnd = new SecureRandom();
}
return srnd;
}
};
private ThreadSpecificSecureRandom() {}
public int nextInt(int upperBound) {
SecureRandom secureRandom = SECURE_RANDOM.get();
return secureRandom.nextInt(upperBound);
}
public void setSeed(long seed) {
SecureRandom secureRandom = SECURE_RANDOM.get();
secureRandom.setSeed(seed);
}
}
package com.bruce.threadSpecificStorage;
import org.apache.log4j.PropertyConfigurator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.DecimalFormat;
import java.util.concurrent.*;
/**
* @Author: Bruce
* @Date: 2019/6/4 13:09
* @Version 1.0
*/
public class SmsVerficationCodeSender {
private Logger LOG = LoggerFactory.getLogger(SmsVerficationCodeSender.class);
public static void config() {
PropertyConfigurator.configure("C:/Users/Bruce/Downloads/LearningJavaProject/practice/designpatternconcurrent/src/main/resource/log4j.properties");
}
private static final ExecutorService EXECUTOR =
new ThreadPoolExecutor(1, Runtime.getRuntime().availableProcessors(), 60, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(), new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r, "VerfCodeSender");
t.setDaemon(true);
return t;
}
}, new ThreadPoolExecutor.DiscardPolicy());
public static void main(String[] args) {
config();
SmsVerficationCodeSender client = new SmsVerficationCodeSender();
client.sendVerificationSms("1223049442");
client.sendVerificationSms("1234442343");
client.sendVerificationSms("1988323232");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void sendVerificationSms(final String msisdn) {
Runnable task = new Runnable() {
@Override
public void run() {
int verificationCode = ThreadSpecificSecureRandom.INSTANCE.nextInt(99999);
DecimalFormat df = new DecimalFormat("00000");
String txtVerCode = df.format(verificationCode);
sendSms(msisdn, txtVerCode);
}
};
EXECUTOR.submit(task);
}
private void sendSms(String msisdn, String verificationCode) {
LOG.info("Sending verification code " + verificationCode + " to " + msisdn);
}
}
线程持有存储模式可以在不使用锁的情况下实现线程安全,避免锁的开销及相关问题,如上下文切换、死锁
需要注意的是,模式隐藏了系统结果,使应用难以理解。
模式应用场景:
1. 需要使用非线程安全对象,但是不希望引入锁
2. 使用线程安全对象,但希望避免其使用的锁的开销和相关问题
3. 隐式参数传递
4. 特定于线程的单例模式
参考资料