2015-04-06 2 views
0

Я изучаю java Threads, я перехожу к уроку о значениях локальных потоков, и я решил создать программу, которая их использует. Я установил значение локального потока в конструкторе (конструктор потока), чтобы показать его на экране, чтобы проверить, что он сработал, но когда я запускаю потоки, локальные значения обращаются к NULL, поэтому я получаю NullPointerException. Я что-то пропустил, или я могу установить только значения локального потока в методе старта?Выполняет ли настройку переменной ThreadLocal в конструкторе?

package practice; 
import static java.lang.System.out; 
import java.util.Scanner; 
class Try 
{ 
    Thread a1,a2,a3; 
    int x=0; 
    synchronized void change(int who){ 
     out.println("who called"+who); 
     out.println("x initial="+x); 
     x++; 
     out.println("x after="+x); 
    } 
    class now implements Runnable{ 
     ThreadLocal<Integer> id=new ThreadLocal<Integer>(); 
     public void run(){ 
      for(int i=1;i<=25;i++){ 
      out.println("im running id="+id.get()); 
      change(id.get()); 
      out.println("after call me="+id.get()); 
      } 
     } 
     now(int givenid){ 
      out.println("my givenid is "+givenid); 
      id.set(givenid); 
      out.println("my id is "+id.get()); 
     } 
    } 
    public static void main(String[] args) 
    {  
     new Try(); 
    } 


    Try(){ 

    a1=new Thread(new now(1)); 
    a2=new Thread(new now(2)); 
    a1.start(); 
    a2.start(); 
    } 

} 
+0

где у вас используется метод set() или initialValue() метода threadLocal для инициализации threadlocal? –

+0

Не говорите «ThreadLocal _variable_». Хотя верно, что у вас есть переменная, а ее тип - «ThreadLocal », локальность потока не является свойством переменной; Это свойство объекта _object_, к которому относится переменная. ThreadLocal _object_ - это объект с методами get() и set(), которые ссылаются на разные местоположения в зависимости от того, какой поток вызывает их. –

ответ

0

Мне очень нравится ответ на Banthar, но я просто хочу, чтобы показать, что происходит с вашим кодом, добавив лишь несколько отпечатков ...

package threads; 

import static java.lang.System.out; 

class Main { 
    Thread a1, a2, a3; 
    int x = 0; 

    public Main() { 
     out.println("Current thread (in Main's constructor): " + Thread.currentThread().getName()); 
     a1 = new Thread(new MyRunnable(1)); 
     a2 = new Thread(new MyRunnable(2)); 
     a1.start(); 
     a2.start(); 
    } 

    private synchronized void change(int who) { 
     out.println("Current thread (in change() method): " + Thread.currentThread().getName()); 
     out.println("who called" + who); 
     out.println("x initial=" + x); 
     x++; 
     out.println("x after=" + x); 
    } 

    private class MyRunnable implements Runnable { 
     ThreadLocal<Integer> id = new ThreadLocal<Integer>(); 

     public MyRunnable(int givenid) { 
      out.println("Current thread (in MyRunnable's constructor): " + Thread.currentThread().getName()); 
      out.println("my givenid is " + givenid); 
      id.set(givenid); 
      out.println("my id is " + id.get()); 
     } 

     public void run() { 
      out.println("Current thread (in run() method): " + Thread.currentThread().getName()); 
      out.println("im running id=" + id.get()); 
      change(id.get()); 
      out.println("after call me=" + id.get()); 
     } 
    } 

    public static void main(String[] args) { 
     new Main(); 
    } 
} 

И выход:

Current thread (in Main's constructor): main 
Current thread (in MyRunnable's constructor): main 
my givenid is 1 
my id is 1 
Current thread (in MyRunnable's constructor): main 
my givenid is 2 
my id is 2 
Current thread (in run() method): Thread-0 
Current thread (in run() method): Thread-1 
im running id=null 
im running id=null 

Извините за изменение имен.

Как вы можете видеть, когда инстанцирование MyRunnable (Yours now класса) вы установите ThreadLocal в основной нити. Вот почему вы не можете получить к нему доступ через другие потоки.

0

Вот как работают местные жители. Поток локальный как карта из потока в объект. Каждый поток видит свою ценность. Вы устанавливаете значение в основном потоке, и только этот поток увидит это значение.

Я не уверен, чего вы пытаетесь достичь здесь. Местные жители потоков обычно используются для кэширования небезопасных объектов, которые дорого выделяются, и передать их через аргумент невозможно. Обычно они хранятся в статическом поле. Например:

private static ThreadLocal<SimpleDateFormat> FORMAT = new ThreadLocal<SimpleDateFormat>(); 

public static Date parse(final String date) throws ParseException { 
    SimpleDateFormat format = FORMAT.get(); 
    if (format == null) { 
     format = new SimpleDateFormat(); 
     FORMAT.set(format); 
    } 
    return format.parse(date); 
} 

Это будет кэшировать один экземпляр SimpleDateFormat в потоке.

0

Вам необходимо установить «обернутое» значение внутри ThreadLocal. Взгляните на javadocs. Вам нужно позвонить либо set(), либо использовать initialValue(), прежде чем ваш ThreadLocal вернет ничего, кроме null.

Смежные вопросы