这里是多线程加油站
如果对你有帮助,给博主一个免费的点赞以示鼓励
欢迎各位点赞评论收藏⭐️
除了控制资源的访问外,我们还可以通过增加资源来保证所有对象的线程安全。比如,让100个人填写个人信息表,如果只有一支笔,那么大家就得挨个填写,对于管理人员来说,必须保证大家不会去哄抢这仅存的一支笔,否则,谁也填不完。从另外一个角度出发,我们可以准备100支笔,人手一支,那么所有人很快就能完成表格的填写工作。
如果说锁使用的是第一种思路,那么ThreadLocal 使用的就是第二种思路。
private static final SimpleDateFormat sdf = new SimpleDateFormat("yvyyy-MM-dd HH:mm:ss");
public static class ParseDate implements Runnable{
int i=0;
public ParseDate(int i) {this.i=i;}public void run() {
try{
Date t=sdf.parse("2015-03-29 19:29:"+i告60);System.out.print1n(i+":"+t);
]catch (ParseException e){
e.printstackTrace();
public static void main (String[] args) {
ExecutorService es=Executors.newFixedThreadPool(10) ;for(int i=0;i<1000;i++){
es.execute(new ParseDate(i));
}
}
static ThreadLocal<SimpleDateFormat> tl=new ThreadLocal<SimpleDateFormat> ();public static class ParseDate implements Runnable{
int i=0;
public ParseDate(int i){this.i=i;}public void run (){
try {
if(tl.get ()==null){
tl.set(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));)
Date t=tl.get ().parse("2015-03-2919:29:"+i%60);System.out.println(i+":"+t);
}catch (ParseException e){
e.printStackTrace();
}}}
注意:为每一个线程分配不同的对象,需要在应用层面保证ThreadLocal 只起到了简单的容器作用。
public void set(T value){
Thread t =Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null)
map.set(this, value);else
createMap(t, value);
}
public T get (){
Thread t =Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null){
ThreadLocalMap.Entry e = map.getEntry(this);if (e != null)
return (T)e.value;
}
return setInitialValue();
}
/**
*在线程退出前,由系统回调,进行资源清理*/
private void exit(){
if (group != null){
group. threadTerminated (this);group= null;
)
target = null;/*加速资源清理*/
threadLocals = null;
inheritableThreadLocals = null;
inheritedAccessControlContext = null;blocker = null;
uncaughtExceptionHandler = null;
}
public class ThreadLocalDemo_Gc {
static volatile ThreadLocal<SimpleDateFormat>tl = new ThreadLocal<SimpleDateFormat>()
protected void finalize() throws Throwable {
system.out.println (this.toString() +" is ge");
};
static volatile CountDownLatch cd = new CountDownLatch (10000);public static class ParseDate implements Runnable{
int i=0;
public ParseDate(int i){this.i =i;
public void run({
try {
if(tl.get( -=null){
tl.set (new SimpleDateFormat("yvyyy-MM-dd HH:mm:ss"){
protected void finalize() throws Throwable {
System.out.println (this.tostring()+" is gc");
));
System.out.println (Thread.currentThread ().getId() + ":create SimpleDateFormat"");
Date t - tl.get ().parse("2015-03-2919:29:"+i%60);
} catch (ParseException e){
e.printstackTrace(;
l finally{
cd.countDown();
public static void main (string[] args) throws InterruptedException {
Executorservice es = Executors.newFixedThreadPool (10);
for (int i = 0; i <10000;i++)(
es.execute (new ParseDate(i));
cd.await();
System.out.println ( "mission complete! !");tl =null;
System.gc();
System.out.println("first Gc complete! !");
//在设置ThreadLocal的时候,会清除ThreadLocalMap中的无效对象tl = new ThreadLocal();
cd = new CountDownLatch (10000);
for (int i = 0;i<10000; i++){
es.execute(new ParseDate(i);
cd.await(;
Thread.sleep(1000;System.gc(;
System.out. println ("second Gc complete!! ");
}}
static class Entry extends weakReference<ThreadLocal>{
/**The value associated with this ThreadLocal.*/0bject value;
Entry(ThreadLocal k,Object v){
super(k);
value =v;
}}
为每一个线程分配一个独立的对象对系统性能也许是有帮助的。当然了,这也不一定,这完全取决于共享对象的内部逻辑。如果共享对象对于竞争的处理容易引起性能损失,我们还是应该考虑使用ThreadLocal为每个线程分配单独的对象。一个典型的案例就是在多线程下产生随机数。
摘自高并发多线程程序设计一书,大力推荐