我正在尝试使用threadlocal变量使用以下三个不同的线程打印数字0,1,2等等:
0- thread 0
1- Thread 1
2- Thread 2
3- thread 0
4- Thread 1
.
.
下面是我在threadlocal存储中放入一个整数并将其与每个线程递增的原子整数进行比较的代码。
public class alternate123
{
public static void main(String as[])
{
Object ob = new Object ();AtomicInteger t = new AtomicInteger(0);
Thread t1 = new Thread ( new printpattern(t,0),"t0");
Thread t2 = new Thread ( new printpattern(t,1),"t1");
Thread t3 = new Thread ( new printpattern(t,2),"t2" );
t1.start();
t2.start();
t3.start();
}
}
class printpattern implements Runnable
{
//Integer t ;
//Object ob = new Object ();
AtomicInteger ai;
private ThreadLocal<Integer> t = new ThreadLocal<Integer>() ;
public printpattern(AtomicInteger at,Integer i)
{
//
ai=at;
t.set(i);
}
@Override
public void run()
{
// TODO Auto-generated method stub
synchronized (ai) {
while (true)
{if (ai.get()%3==
t.get()) // ----------------------- null pointer exception here
{
try {
ai.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try {
Thread.sleep(300);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Current thread id "+Thread.currentThread().getName()+"value of integer is "+ai.get());;
ai.incrementAndGet();
ai.notify();
}
}
}
}
我在尝试执行t.get()时得到null,而下面是stacktrace:
Exception in thread "t2" java.lang.NullPointerException
at printpattern.run(alternate123.java:46)
at java.lang.Thread.run(Thread.java:619)
Exception in thread "t0" java.lang.NullPointerException
at printpattern.run(alternate123.java:46)
at java.lang.Thread.run(Thread.java:619)
Exception in thread "t1" java.lang.NullPointerException
at printpattern.run(alternate123.java:46)
at java.lang.Thread.run(Thread.java:619)
我使用set方法设置threadlocal变量,我怀疑是错误的。请让我知道可能是什么问题。
答案 0 :(得分:4)
在主线程中调用构造函数,因此为该线程设置了值:您必须在run方法中设置threadlocal值。只需将整数值(构造函数中的i param)存储为printpattern类中的字段,然后在run方法中调用t.set(i)。
P.S。:请将printpattern重命名为PrintPattern - 它是一个类。
答案 1 :(得分:1)
调用set
方法只会为当前的威胁分配值。您正在设置主线程的值。所以它只能从你的主线程中获得。
实际上,在这种情况下,您只需要一个ThreadLocal
的实例,然后您可以将其重用于多个线程。但不管怎样,从各个线程中设置值至关重要。 (即在你的run
方法中)
您可以在某种方式中将ThreadLocal<Integer>
对象视为Map<Thread, Integer>
,其中set方法等同于map.put(Thread.currentThread(), value)
。这并不是内部如何运作,但从功能的角度来看,这几乎就是它的作用。
这是为多个线程重用threadlocal 的示例。 (更改标有//CHANGE x
条评论。)
public class Alternate123 {
public static void main(String as[]) {
// CHANGE 1: create only 1 threadlocal instance.
ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>();
// CHANGE 2: pass the threadlocal to the individual threads.
Thread t1 = new Thread(new printpattern(0, threadLocal), "t0");
Thread t2 = new Thread(new printpattern(1, threadLocal), "t1");
Thread t3 = new Thread(new printpattern(2, threadLocal), "t2");
t1.start();
t2.start();
t3.start();
}
}
class printpattern implements Runnable {
// CHANGE 3: keep track of the initial value
Integer startValue;
ThreadLocal<Integer> threadLocal;
AtomicInteger ai = new AtomicInteger();
public printpattern(Integer i, ThreadLocal<Integer> threadLocal) {
// CHANGE 4: don't assign the value to the threadlocal yet.
// Because we are still in the main-thread when we reach this point.
this.startValue = i;
this.threadLocal = threadLocal;
}
@Override
public void run() {
// CHANGE 5: Assign the initial value to the threadlocal
// this time we are doing it from within the individual threads.
if (this.threadLocal.get() == null) {
this.threadLocal.set(startValue);
}
synchronized (ai) {
while (true) {
if (ai.get() % 3 == t.get()) {
try {
ai.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
// CHANGE 6: I had to change something here to make it compile. Not really relevant.
System.out.println("Current thread id " + Thread.currentThread().getName() + "value of integer is ...");
ai.incrementAndGet();
ai.notify();
}
}
}
}