2013-08-23 16 views
5

to pytanie jest prawdopodobnie dość łatwo odpowiedzieć, ale po prostu nie rozumiem. Obniżyłem swój problem, dopóki ten mały fragment kodu nie został, aby znaleźć "pochodzenie" tego problemu: Próbuję wypełnić ArrayList of Threads pętlą.Java - Wypełnianie ArrayList of Threads pętlą

public static int u=0; 

public void test(){ 
    while (u <10) { 
     synchronized(threadList){ 
      threadList.add(u, new Thread(){     
       @Override public void run(){      
        System.out.println("Thread at Index: " + u);      
       } 
      }); 
     } 
     u++;    
    } 

    threadList.get(2).start();  
} 

W ostatniej linii chciałem przetestować powyższą pętlę, rozpoczynając wątek na indeksie "2". Spodziewam się, że konsola wyświetli "Thread at Index: 2", ale zamiast tego jest wyświetlana: "Thread at Index: 10" Bez względu na to, którą liczbę całkowitą piszę w ".get (int)" - metoda, I otrzymać indeks "10".

Dlaczego tak jest? I jak to naprawić?

Tworzenie wątków wydaje się działać ... więc jest liczbą całkowitą "u" problemu?

Doceniam każdą pomoc! Z góry dziękuję!

+8

'u' jest statyczna, więc zawsze otrzymasz bieżącą wartość (' 10', gdy program działa). Nie zapisujesz wartości użytej podczas tworzenia nici w dowolnym miejscu. –

+0

Jeśli na twoją listę wątków można uzyskać dostęp tylko z jednego wątku (głównego wątku?), Nie musisz synchronizować z użyciem tej listy. – Raedwald

Odpowiedz

9

Kiedy można odwołać u w swojej metodzie

@Override public void run(){      
    System.out.println("Thread at Index: " + u);      
} 

Aktualna wartość u są pobierane run. Na końcu pętli i po uruchomieniu wątku ta wartość to 10.

Spróbuj następującą

public static int u = 0; 

public void test(){ 
    while (u <10) { 
     synchronized(threadList){ 
      threadList.add(u, new Thread(){  
       int i = u; 

       @Override public void run(){      
        System.out.println("Thread at Index: " + i);      
       } 
      }); 
     } 
     u++;    
    } 

    threadList.get(2).start();  
} 

W swojej anonimowej Thread klasy, jesteś ustawienie pola instancji i wartości u ma gdy konstruktor nazywa i drukowanie tę wartość, gdy run() jest wykonywany.

Użytkownik odwołuje się do u w kontekście, który nie został jeszcze wykonany, wątku. Kiedy zostanie wywołana metoda run(), program oceni zmienną u, ale w tym momencie wykonania programu jego wartość będzie równa 10. Jeśli zamiast tego wykonasz powyższe, zmienna i będzie utrzymywać wartość na ten dokładny moment. Dzieje się tak dlatego, że po rozpoczęciu i uruchomieniu nowego Thread następuje inicjalizacja pola i natychmiast zostaje obliczona u.

+0

Dzięki za szybką odpowiedź. Tak, to działa! Dziękuję Ci! Ale tak naprawdę nie rozumiem, dlaczego działa z "int i". ..czy to dlatego, że int jest statyczne i zdefiniowane poza metodą, a int pozostaje w metodzie i nie można uzyskać do niego dostępu z zewnątrz i dlatego ma zawsze pewną wartość podczas pracy pętli? Przepraszamy za mój zły angielski. – SoundOfTheTuner

+0

Drobna poprawa dla małych Runnables w ten sposób - ustaw zmienne instancji (i w tym przykładzie) 'final' dla jasności i bezpieczeństwa wątków. – user949300

+0

@music zobacz moją edycję w odpowiedzi na pytanie –

1
while (u <10) { 
     synchronized(threadList){ 

      final int u_final = u; 

      threadList.add(u, new Thread(){     
       @Override public void run(){      
        System.out.println("Thread at Index: " + u_final); 
       } 
      }); 
     } 
     u++;    
    } 

ze zmienną final, to jest jasne, co będzie jego wartość, ponieważ nigdy nie zmieni.

+0

Och, widzę ... dzięki! Więc, jeśli dobrze rozumiem wszystko: Byłoby lepiej, gdybym użył pętli for, ponieważ zawiera zmienną pętli (na przykład "int i = 0;"), która pozostaje w tej pętli na zawsze i zmienia jej wartość tylko podczas pracy pętli? – SoundOfTheTuner

+0

@ MuSiCkiLL8or Nie byłbyś w stanie użyć indeksu pętli for 'i' w wątku bezpośrednio, ponieważ należy on do innego zakresu. Spróbuj, nie skompiluje się. –

-1

spróbować dwóch sposobów:

package com.test; 

import java.util.ArrayList; 

public class TestThread5 { 
    public static int u=0; 
    public ArrayList<Thread> threadList = new ArrayList<>(); 
    public void test() throws InterruptedException{ 
     while (u <10) { 
      synchronized(threadList){ 
       threadList.add(u, new Thread(){     
        @Override public void run(){      
         System.out.println("Thread at Index: " + u);      
        } 
       }); 
      } 
      u++;    
     } 
     for (u = 0; u < 10; u++) { 
      Thread thread = threadList.get(u); 
      thread.start(); 
      thread.join(); 
     } 
     // threadList.get(2).start();  
    } 
    public static void main(String[] args) throws InterruptedException { 
     new TestThread5().test(); 
    } 
} 

i

package com.test; 

import java.util.ArrayList; 
import java.util.Iterator; 

public class TestThread4 { 
    public int u=0; 
    public ArrayList<Thread> threadList = new ArrayList<>(); 
    public void test() throws InterruptedException{ 
     while (u <10) { 
      synchronized(threadList){ 
       threadList.add(u, new MyThread(u)); 
      } 
      u++;    
     } 
     for(Thread thread :threadList){ 
      thread.start(); 
      thread.join(); 
     } 
     // ((Thread) threadList.get(2)).start();  
    } 
    public static void main(String[] args) throws InterruptedException { 
     new TestThread4().test(); 
    } 
} 
class MyThread extends Thread{ 
    private int u; 
    public MyThread(int u){ 
     this.u = u; 
    } 
    @Override 
    public void run() { 
     System.out.println("Thread at Index: " + u); 
    } 

}