java线程 在其他对象上同步、线程本地存储ThreadLocal:thinking in java4 21.3.6
package org.rui.thread.concurrency;
/**
* 在其他对象上同步
* synchronized 块必须给定一个在其上进行同步的对象,并且最合理的方式是,使用其方法正在被调用的当前对象
* :synchronized(this), 在 这种方式中,如果获得了synchronized块上的锁,
* 那么该对象其他的synchronized方法和临界区就不能被调用了。
* 因此,如果在this上同步,临界区的效果就会直接缩小在同步的范围内.
*
* 有时必须在另一个对象上同步,但是如果你要这么做,就必须确保所有相关任务都是在同一个对象上同步的。
* 下面的示例演示了两个任务可以同时进入同一个对象,
* 只要这个对象上的方法是在不同中的锁上同步的即可
* @author lenovo
*
*/
class DualSynch
{
private Object syncObject=new Object();
public synchronized void f()
{
for(int i=0;i<5;i++)
{
System.out.println("f()");
Thread.yield();
}
}
public void g()
{
synchronized (syncObject)
{
for(int i=0;i<5;i++)
{
System.out.println("g()");
Thread.yield();
}
}
}
}
public class SyncObject
{
public static void main(String[] args)
{
final DualSynch ds =new DualSynch();
//另一个 线程
new Thread()
{
public void run()
{
ds.f();
};
}.start();
//g()
ds.g();
}
}
/**
* DualSyn.f()通过同步整个方法 在this上同步,面g()有一个在syncObject上同步的synchronized块
* 因此,这两个同步是互相独立的。通过在main()中创建调用f()的thread对这一点进行了演示,
* 因此,这两个同步是互相独立的.从输出中可以看到,
* 这两个方法在同时运行,因此任何一个方法都没有因为对另一个方法的同步而被阻塞
*
*
* output(sample)
g()
f()
g()
f()
f()
f()
f()
g()
g()
g()
*/
package org.rui.thread.concurrency;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
* 线程本地存存储
*
* 防步任务共享资源上产生冲突的第二种方式是根除对变量共享。
* 线程本地存储是一种自动化机制,可以为使用相同变量的每个不同的线程都创建不同的存储。因此,
* 如果你有5个线程都要使用变量X所表示的对象,那线程本地存储就会生成5个用于x的不同的存储块。主要是,
* 它们使得你可以将状态与线程关联起来。
* @author lenovo
*
*/
class Accessor implements Runnable
{
private final int id;
public Accessor(int idn){id=idn;}
@Override
public void run() {
while(!Thread.currentThread().isInterrupted())
{
ThreadLocalVariableHolder.incrment();
System.out.println(this);
Thread.yield();
}
}
//toString()
@Override
public String toString() {
return "#"+id+": "+ThreadLocalVariableHolder.get();
}
}
///
public class ThreadLocalVariableHolder {
private static ThreadLocal<Integer> value=
new ThreadLocal<Integer>()
{
private Random rand=new Random(47);
protected synchronized Integer initialValue()
{
return rand.nextInt(10000);
}
};
public static void incrment()
{
value.set(value.get()+1);
}
public static int get(){return value.get();}
public static void main(String[] args) throws Exception
{
ExecutorService exec=Executors.newCachedThreadPool();
for(int i=0;i<5;i++)
exec.execute(new Accessor(i));
TimeUnit.SECONDS.sleep(3);//run for a while
exec.shutdownNow();// all accessors will quit
}
}
/**
* ThreadLocal对象通常当作静态域存储。在创建ThreadLocal时,你只能通过get() set()方法来访问该对象的内容,
* 其中,get()方法将返回与其线程相关联的对象副本,而set会将参数插入到为其线程存储的对象中,并返回存储中原有的对象。
* increment()和get()方法在这里演示了这点, ThreadLocal保证不会出现竞争条件.
*
*
*
* output(sample)
#1: 39807
#1: 39808
#1: 39809
#1: 39810
#1: 39811
#1: 39812
#0: 44495
#4: 41633
#4: 41634
#4: 41635
#4: 41636
#4: 41637
#4: 41638
#4: 41639
#4: 41640
*/