Wielowątkowość i moment zatrzymania działania wątku

0

Witam,
tytułem wstępu..
ostatnio na zajęciach uczelnianych mam okazję 'zgłębiać' wiedzę w temacie XML'a (XPath, XQuery, XSLT ..). Teraz przyszedł czas na zbugowanie jakiejś aplikacji korzystającej z bazy xml, i wybór odgórnie padł na Jave, bo m.in. przykłady z których korzystamy są przygotowane pod ten język..

Wracając do wielowątkowości.. Mam następujący przykład:

package org.basex.examples.server;

import java.io.*;
import java.util.*;

import org.basex.*;
import org.basex.server.*;

/**
 * This class connects multiple clients to one server instance.
 * It sets up three clients with read/write access to the database.
 * Database information will be shown before and after the
 * clients have been run.
 *
 * @author BaseX Team 2005-14, BSD License
 */
public final class ServerConcurrency {
  /**
   * Main method of the example class.
   * @param args (ignored) command-line arguments
   * @throws Exception exception
   */
  public static void main(final String[] args) throws Exception {
    new ServerConcurrency().run();
  }

  /**
   * Runs the example code.
   * @throws Exception on error.
   */
  void run() throws Exception {
    System.out.println("=== ServerConcurrency ===");

    // ------------------------------------------------------------------------
    // Start server
    System.out.println("\n* Start server.");

    BaseXServer server = new BaseXServer();

    // ------------------------------------------------------------------------
    // Create a client session with host name, port, user name and password
    System.out.println("\n* Create a client session.");

    ClientSession session =
      new ClientSession("localhost", 1984, "admin", "admin", System.out);

    // ------------------------------------------------------------------------
    // Create a database
    System.out.println("\n* Create a database.");

    send("CREATE DB input src/main/resources/xml/input.xml", session);

    // ------------------------------------------------------------------------
    // Setup some clients that simultaneously read and write from the database
    System.out.println("\n* Run one reader and two writers threads.");

    ClientExample reader1 = new ClientExample("//li");
    ClientExample writer1 = new ClientExample("insert node " +
        "<li>new node</li> as last into /html/body//ul");
    ClientExample writer2 = new ClientExample("insert node " +
        "<new>One more</new> as last into /html/body");

    // -------------------------------------------------------------------------
    // Let the clients run their query several times:
    Thread.sleep(2000);

    // ------------------------------------------------------------------------
    // Stop the clients
    System.out.println("\n* Stop client threads.");

    reader1.stop();
    writer1.stop();
    writer2.stop();

    Thread.sleep(1000);

    // -------------------------------------------------------------------------
    // Show modified database contents
    System.out.println("\n* Show modified database contents:");

    send("XQUERY //li", session);

    // ----------------------------------------------------------------------
    // Drop the database
    System.out.println("\n* Drop the database.");

    send("DROP DB input", session);

    // ------------------------------------------------------------------------
    // Close the client session
    System.out.println("\n* Close the client session.");

    session.close();

    // ------------------------------------------------------------------------
    // Stop the server
    System.out.println("\n* Stop server.");

    server.stop();
  }

  /**
   * Processes the specified command on the server and returns the output
   * or command info.
   * @param cmd command to be executed
   * @param cs client session reference
   * @throws IOException I/O exception
   */
  static void send(final String cmd, final ClientSession cs) throws IOException {
    // ------------------------------------------------------------------------
    // Execute the command
    cs.execute(cmd);
  }

  /**
   * This class simulates a database client.
   * Within a thread, a query is run several times until the thread is stopped.
   */
  private final class ClientExample {
    /** Set to false to stop the Client from running.*/
    boolean running = true;
    /** Random sleep time generator.*/
    Random r = new Random();

    /**
     * Constructor.
     * @param query query to be run
     * @throws IOException I/O exception
     */
    ClientExample(final String query) throws IOException {
      // ----------------------------------------------------------------------
      // Create a client session and open database
      final ClientSession session =
        new ClientSession("localhost", 1984, "admin", "admin");
      send("OPEN input", session);

      // ----------------------------------------------------------------------
      // Create and run the query thread

      new Thread() {
        @Override
        public void run() {
          try {
            // ----------------------------------------------------------------
            // Loop until the running flag has been invalidated
            while(running) {
              // Run the specified query
              send("XQUERY " + query, session);

              // Wait for a random time
              Thread.sleep(r.nextInt(500));
            }
            // ----------------------------------------------------------------
            // Close the client session
            session.close();
          } catch(final Exception ex) {
            ex.printStackTrace();
          }
        }
      }.start();
    }

    /**
     * Quits the client thread.
     */
    void stop() {
      running = false;
    }
  }
}

Przykład jest w porządku. Jednak analizując go i modyfikując go do własnych 'potrzeb' napotkałem na problem - wykonując zapytania w np. 3 wątkach i 'wyrzucając' wynik do konsoli, zostają one wyświetlone w różnej kolejności..

Z tego co wiem o wątkach (a wiem niewiele) to jest to normalny stan rzeczy.. Ja ten problem 'niezdarnie' próbowałem obejść poprzez odpowiednie usypianie wątku, co z resztą jest tutaj robione i co w szczególnie określonych warunkach działa..

Jaki mam problem i co chciałbym osiągnąć?

Przykład:
Zlecam uruchomienie 10-ciu zapytań, każde w osobnym wątku. I teraz mam taką sytuację, że niektóre zapytania które wykonują się szybko zostaną wyświetlone kilka razy zanim kod 'dojdzie' do metody zatrzymującej dany wątek (bo jak widać zapytania wykonywane są w pętli -> white(running)).

Ja chciałbym oczywiście uzyskać taki efekt, że dane zapytanie jest wykonywane tylko raz przez wątek i po jednokrotnym wykonaniu zapytania ma nastąpić zakończenie tego wątku i zwrócenie wyniku.

Z tego co wiem, istnieją różne 'komendy' służące do tego typu rzeczy np. czekanie aż każdy wątek zostanie zakończony, itd.. Jednakże co ja potrzebuje zmienić/dodać w kodzie aby zaczął on działać tak jak tego oczekuje ?

ps. Ogólnie to jest 'wzorcowy' przykład z dokumentacji.. Ja już go sobie troche u siebie 'porozdzielałem' na osobne pliki, dodałem konkretne zapytania, etc.. ale to szczegóły i nie chcialem niepotrzebne zaciemniać problemu..

ps2. Teraz pisząc ten post, pomyślałem czy mógłbym np. w pętli while od razu po wykonaniu zapytania zmienić running na false.. albo w ogóle wyrzucić tą pętle i wtedy to raczej wykona się raz.. Tylko co jeśli np. 5 zapytań uruchomię w jednym wątku.. (problem raczej wróci..)

Czekam na sugestie/jakieś rozwiązania (jeżeli mógłbym prosić to chciałbym otrzymać trochę bardziej rozbudowaną i dopasowaną do wyżej przytoczonego przykładu poradę.. Bo odpowiedź w stylu "skorzystaj z metody join" nie wiele mi pomoże..)

0
  1. Wywalenie while to chyba oczywista rzecz którą powinieneś zrobić.
  2. Oprócz tego nie bardzo rozumiem co chcesz osiągnąć. Nie chcesz żeby dane logowane na konsoli się "mieszały"? To synchronizuj dostęp do konsoli -> w danej chwili pisać może tylko jeden wątek.
0

@Shalom - odnośnie "synchronizacji dostępu do konsoli" to chodziło o coś takiego:

public void safePrintln(String s) {
  synchronized (System.out) {
    System.out.println(s);
  }
}

?

0

Mniej więcej tak.

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