Zapętlony wątek metody main

0

Mam taki kawałek kodu. Mam wątek główny który tworzy trzy wątki podrzędne, czy pętla która jest zadeklarowana z warunkiem count > readStringCount.get w wątku głównym zapętla ten wątek główny ? który czeka na to aż wątek podrzędny który korzysta ze pola volatile BufferedReadera? wykona akcje wprowadzenia ciągu przez użytkownika do konsoli? Rozumiem mniej więcej samo działanie słowa kluczowego volatile, ale chciałbym wiedzieć czy dobrze myślę.

public static volatile AtomicInteger readStringCount = new AtomicInteger(0);
   public static volatile BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

   public static void main(String[] args) throws IOException {


       int count = Integer.parseInt(reader.readLine());

       // Inicjuje wątki
       ReaderThread consoleReader1 = new ReaderThread();
       ReaderThread consoleReader2 = new ReaderThread();
       ReaderThread consoleReader3 = new ReaderThread();

       consoleReader1.start();
       consoleReader2.start();
       consoleReader3.start();

       while (count > readStringCount.get()) {
       }

       consoleReader1.interrupt();
       consoleReader2.interrupt();
       consoleReader3.interrupt();
       System.out.println("#1:" + consoleReader1);
       System.out.println("#2:" + consoleReader2);
       System.out.println("#3:" + consoleReader3);

       reader.close();
   }

   public static class ReaderThread extends Thread {
       private List<String> result = new ArrayList<>();

       public void run() {

           while (true) {
               try {
                   String s;
                   if ((s = reader.readLine ()) != null) {
                       readStringCount.getAndIncrement ();
                       result.add (s);
                   }


               } catch (IOException e) {


                   throw new RuntimeException (e);
               }
           }
       }

       @Override
       public String toString() {
           return result.toString();
       }
   }
}
2

Jak interrupt wbije ci się między te dwie linie:

   readStringCount.getAndIncrement ();
   result.add (s);

to cały misterny plan c''' jasny strzelił.

Z mniej istotnych błędów kardynalnych to nie dziedziczy sie po Thread tylko implementuje Runnable. I pewnie ktoś jeszcze powie że to dość dziwny sposób zwracania danych z wątku (lepsza by była jakaś globalna synchronizowana struktura (kolejka/mapa) czy coś)

1
Virus_ napisał(a):

Rozumiem mniej więcej samo działanie słowa kluczowego volatile, ale chciałbym wiedzieć czy dobrze myślę.

Z tego co widzę absolutnie nie rozumiesz.
volatile jedynie oznacza że fragment:
x=true; while(x) { ... }
w przypadku braku zmiany x wewnątrz pętli nie zostanie zoptymalizowany do:
while(true) { ... }
i to wszystko.

2

O boziu...

public static volatile AtomicInteger readStringCount = new AtomicInteger(0);
public static volatile BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

volatile w tych miejscach nie robi absolutnie nic. Przecież nie zmieniasz referencji na które wskazują readStringCount i reader

public static void main(String[] args) throws IOException {


    int count = Integer.parseInt(reader.readLine());

    // Inicjuje wątki
    ReaderThread consoleReader1 = new ReaderThread();
    ReaderThread consoleReader2 = new ReaderThread();
    ReaderThread consoleReader3 = new ReaderThread();

    consoleReader1.start();
    consoleReader2.start();
    consoleReader3.start();

    while (count > readStringCount.get()) {
    }

Czy aby na 100% chcesz, żeby wątek główny leciał bez wytchnienia?

    consoleReader1.interrupt();
    consoleReader2.interrupt();
    consoleReader3.interrupt();

Co twoim zdaniem robi interrupt()? Bo w tym przypadku również raczej niewiele.

    System.out.println("#1:" + consoleReader1);
    System.out.println("#2:" + consoleReader2);
    System.out.println("#3:" + consoleReader3);

    reader.close();
}

public static class ReaderThread extends Thread {
    private List<String> result = new ArrayList<>();

    public void run() {

        while (true) {

Kiedy skończy się ta ^^^ pętla i cały wątek?

            try {
                String s;
                if ((s = reader.readLine ()) != null) {
                    readStringCount.getAndIncrement ();
                    result.add (s);
                }


            } catch (IOException e) { 
                throw new RuntimeException (e);
            }
        }
    }

    @Override
    public String toString() {
        return result.toString();
    }
}

}

Trochę zgaduję co się tu dzieje, nie chce mi się tego sprawdzać, ale:
Twoje interrupt zmienia flagę w wątku na interrupted == true.
W samym wątku, nie masz żadnego sprawdzenia tej flagi, więc możesz sobie tę flagę ustawiać na co chcesz, a i skoro z niej nie korzystasz, to jest sobie ustawiona i tyle.

Pewnie chodzi co o coś w tym kształcie:

public class Main {

    public static void main(String[] args) throws InterruptedException {
        AtomicInteger counter = new AtomicInteger(0);
        Thread t1 = new MyThread(counter, 1);
        Thread t2 = new MyThread(counter, 2);
        t1.start();
        t2.start();
        Thread.sleep(100);
        t1.interrupt();
        t2.interrupt();

        t1.join();
        t2.join();

    }

    public static class MyThread extends Thread {
        private final AtomicInteger counter;
        private final int threadId;

        public MyThread(AtomicInteger counter, int threadId) {
            this.counter = counter;
            this.threadId = threadId;
        }

        @Override
        public void run() {
            while (!interrupted()) {
                System.out.println("Hello I'm, thread "+ threadId + " the value is " + counter.getAndIncrement());
            }
        }
    }
}
0

Obstawiałbym że chodzi o coś takiego:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicInteger;

public class ThreadRead
{
   public static BufferedReader Reader=new BufferedReader(new InputStreamReader(System.in));
   public final AtomicInteger Count=new AtomicInteger();

   private void loop(int id)
   {
      final ArrayList<String> result=new ArrayList<>();
      while(true)
      {
         String last=null;
         synchronized(Count)
         {
            if(Count.decrementAndGet()<0) break;
            try { last=Reader.readLine(); }
            catch(IOException ex) { System.out.println("exception: "+id); }
         }
         result.add(last);
         try { Thread.sleep(1); } catch(Exception ex){}
      }
      synchronized(this)
      {
         System.out.println("Thread with id: "+id+" read:");
         int i=0;
         for(String str:result) System.out.println("\t"+(i++)+" \""+str+"\"");
      }
   }

   private void run()
   {
      for(int i=0;i<3;++i)
      {
         final int id=i+1;
         new Thread(()->loop(id)).start();
      }
   }

   private ThreadRead(int count) { Count.set(count); }

   public static void main(String[] args)
   {
      try { new ThreadRead(Integer.parseInt(Reader.readLine())).run(); }
      catch(IOException ex) { System.out.println("First line must be number"); }
   }
}

/* example:
10
zero
one
two
three
four
five
six
seven
eight
nine
*/

1 użytkowników online, w tym zalogowanych: 0, gości: 1