简体   繁体   English

如何使Java线程始终在另一个线程之前运行?

[英]How can I make a Java thread always run before another thread?

In my program, when a user enters a number, the program sends that number to the server through sockets and the server sends back data matching that number. 在我的程序中,当用户输入数字时,程序会通过套接字将该数字发送到服务器,然后服务器将与该数字匹配的数据发送回去。 The number represents a service level. 该数字表示服务级别。 The thread which has the IncomingReader() instance as its runnable then reads what was sent from the server, stores it an arraylist(details). 然后将具有IncomingReader()实例作为其可运行对象的线程读取从服务器发送的内容,并将其存储在arraylist(详细信息)中。 I then create objects of class MyClients using the data in the details arraylist. 然后,我使用详细信息数组列表中的数据创建类MyClients的对象。 My problem is that the loop which creates the objects runs before the thread that reads data from the server runs. 我的问题是,创建对象的循环在从服务器读取数据的线程运行之前运行。 How can I make the thread that reads from the server run before the loop that creates the objects? 如何使从服务器读取的线程在创建对象的循环之前运行? The code is as follows: (I've removed the code for the GUI for the sake of being concise) 代码如下:(为了简洁起见,我删除了GUI的代码)

public class SearchClients {

JFrame frame;
private JTextField textField;
private JTextField textField_1;
private JTextField textField_2;
private JTextField textField_3;


BufferedReader reader;
PrintWriter writer;
Socket sock;

 static ArrayList<String> details = new ArrayList<String>();

public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
        public void run() {
            try {
                SearchClients window = new SearchClients();
                window.frame.setVisible(true);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    });
}

public SearchClients() {
    initialize();
}

private void initialize() {

    setUpNetworking();
    Thread readerThread = new Thread(new IncomingReader());
    readerThread.start();


    JButton btnSearchByService = new JButton("Search By Service Level");

    btnSearchByService.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent arg0) {
            searchByServiceLevel();
        }
    });

}

public void searchByServiceLevel() {

    try {
        writer.println("SEARCH BY SERVICE LEVEL");
        writer.println(textField_1.getText());
        writer.flush();


    }
    catch (Exception ex) {
        ex.printStackTrace();
    }



    JPanel nameSearchPane = new JPanel(new BorderLayout());

    frame.setExtendedState(Frame.MAXIMIZED_BOTH);
    frame.setContentPane(nameSearchPane);
    frame.invalidate();
    frame.validate();

    String[] columns = {"Name", "Phone Number", "Address", "District", "County", "Village", "Installation Date", "Energy Store", "Service Level", "Account Balance", "Months Owed", "Next Payment Date"};

    ArrayList<MyClients> clientDetails = new ArrayList<MyClients>();
    for(int y = 0; y < details.size(); y++) {
        MyClients client = new MyClients();
        client.name = details.get(y);
        client.phone_number = details.get(++y);
        client.address = details.get(++y);
        client.district = details.get(++y);
        client.county = details.get(++y);
        client.village = details.get(++y);
        client.installation_date = details.get(++y);
        client.energy_store = details.get(++y);
        client.service_level = details.get(++y);
        client.next_payment_date = details.get(++y);
        client.account_balance = details.get(++y);
        client.months_owed = details.get(++y);
        clientDetails.add(client);

    }

    details.clear();

//      Check if any data was returned from the database
    if(clientDetails.isEmpty()) {
        JOptionPane.showMessageDialog(frame, "A client with that service level was not found.\n Try service level: 1, 2, 3 or 4.");

        frame.setVisible(false);
        SearchClients search = new SearchClients();
        search.frame.setVisible(true);
    }

    String[][] clients = new String[100][100];

    for(int x = 0; x < clientDetails.size(); x++) {
        clients[x][0] = clientDetails.get(x).name;
        clients[x][1] = clientDetails.get(x).phone_number;
        clients[x][2] = clientDetails.get(x).address;
        clients[x][3] = clientDetails.get(x).district;
        clients[x][4] = clientDetails.get(x).county;
        clients[x][5] = clientDetails.get(x).village;
        clients[x][6] = clientDetails.get(x).installation_date.toString();
        clients[x][7] = clientDetails.get(x).energy_store;
        clients[x][8] = clientDetails.get(x).service_level;
        clients[x][9] = clientDetails.get(x).account_balance;
        clients[x][10] = clientDetails.get(x).months_owed;
        clients[x][11] = clientDetails.get(x).next_payment_date.toString(); 

    }

    JTable table = new JTable(clients, columns);
    JScrollPane tableContainer = new JScrollPane(table);
    nameSearchPane.add(tableContainer, BorderLayout.CENTER);

}

private void setUpNetworking() {
    try {
        sock = new Socket("127.0.0.1", 5000);
        InputStreamReader streamReader = new InputStreamReader(
                sock.getInputStream());
        reader = new BufferedReader(streamReader);
        writer = new PrintWriter(sock.getOutputStream());
        System.out.println("Networking established");
    } catch (IOException ex) {
        ex.printStackTrace();
    }
}


class IncomingReader implements Runnable {
    public void run() {
        String message;
        try {
            while ((message = reader.readLine()) != null) {
                details.add(message);

            }
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
}

class MyClients {
    String name = "";
    String phone_number = "";
    String address = "";
    String district = "";
    String county = "";
    String village = "";
    String installation_date = "";
    String energy_store = "";
    String service_level = "";
    String next_payment_date = "";
    String account_balance = "";
    String months_owed = "";
    String clientID = "";
}

}

Why do you have them in separate threads? 为什么将它们放在单独的线程中?

Usually, if the execution of B relies on the execution of A, then having A and B in separate threads is overhead you don't need, they are effectively sequential. 通常,如果B的执行依赖于A的执行,那么您就不需要在单独的线程中拥有A和B了,它们实际上是顺序的。

Now that's out of the way, it looks like you're trying to write a server. 既然这样,看来您正在尝试编写服务器。 Typically, you'd run the "server" as its own application. 通常,您将“服务器”作为其自己的应用程序运行。 It would open a socket, and wait for input. 它将打开一个套接字,然后等待输入。 On input, it'd spin up a worker thread (so that the server can continue to receive connections on the socket). 在输入时,它将启动一个工作线程(以便服务器可以继续在套接字上接收连接)。 And then send the information back via the socket to the calling program. 然后通过套接字将信息发送回调用程序。 The calling program sends information to the server, and "waits" until the information comes back. 调用程序将信息发送到服务器,并“等待”直到信息返回。

So there's a few things you probably want to do. 因此,您可能需要做一些事情。

  • you probably want to have your "threads" be actual different applications 您可能希望您的“线程”成为实际的不同应用程序
  • you need to "wait" in your sending thread either by: 您需要通过以下方式在发送线程中“等待”:

    • some form of block on the communication response 对通讯响应的某种形式的阻止
    • a callback object which can be invoked on response 可以在响应时调用的回调对象
    • something in your application loop which queries for a response. 您的应用程序循环中需要查询响应的内容。

As a final comment, at any point you need to run thread A before thread B, you're doing your threading wrong. 最后,在任何时候都需要在线程B之前运行线程A,这是在做错误的线程。 and need to stop and look at why :) 并需要停下来看看原因:)

How can I make the thread that reads from the server run before the loop that creates the objects? 如何使从服务器读取的线程在创建对象的循环之前运行?

This has nothing to do with thread "order of running" and everything to do with state of the object . 这与线程“运行顺序”无关,与对象的状态无关。 In fact your focusing on thread order I think has prevented you from thinking of the true nature of your problem. 实际上,我认为您对线程顺序的关注使您无法考虑问题的本质。 You need to make your program behave appropriately to incoming data depending on its state which changes depending on what is received and what it is doing. 您需要根据传入数据的状态使程序对传入数据表现适当的状态,该状态根据接收到的数据和正在执行的操作而变化。 Now on to what specific state problem you have: 现在介绍您遇到的具体状态问题:

Producer-Consumer Problem: 生产者-消费者问题:

Yours is a classic producer-consumer problem, and so what you want to do is not use an ArrayList of details but rather a Queue. 您的问题是典型的生产者-消费者问题,因此您要做的不是使用详细信息的ArrayList,而是使用Queue。 Properly used, the consumer, your client, and its object production loop will be blocked when the queue of Details is empty and will wait for Details to arrive before creating objects. 如果详细信息队列为空,则使用者,客户,客户及其对象生产循环的正确使用将被阻塞,并在创建对象之前等待详细信息到达。

As an aside, whatever collection or technique you use, your collection of Details should absolutely not be static . 顺便说一句,无论您使用什么集合或技术,您的Details集合绝对不应是静态的 This will limit your ability to use the collection and associated methods in any OOP fashion. 这将限制您以任何OOP方式使用集合和关联方法的能力。

You can use the join method of class Thread . 您可以使用Thread类的join方法。 It will wait until the thread completes execution and then return. 它将等待直到线程完成执行,然后返回。 After that, you can start the second thread. 之后,您可以启动第二个线程。

I am not sure how you can make sure A always run before B, but there is a method of making sure B always run after A. 我不确定如何确保A始终在B之前运行,但是有一种方法可以确保B始终在A之后运行。

Using CountDownLatch . 使用CountDownLatch

See following example modified on this , The main thread will wait and block until cacheService thread started . 参见下面对此进行修改的示例,主线程将等待并阻塞,直到cacheService线程启动为止。

    public class CountDownLatchDemo {

    public static void main(String args[]) {
       final CountDownLatch latch = new CountDownLatch(1);
       Thread cacheService = new Thread(new Service("CacheService", 1000, latch));       
       cacheService.start(); //separate thread will initialize CacheService

       try{
            latch.await();  //main thread is waiting on CountDownLatch to finish
            System.out.println("All services are up, Application is starting now");
       }catch(InterruptedException ie){
           ie.printStackTrace();
       }

    }

}

/**
 * Service class which will be executed by Thread using CountDownLatch synchronizer.
 */
class Service implements Runnable{
    private final String name;
    private final int timeToStart;
    private final CountDownLatch latch;

    public Service(String name, int timeToStart, CountDownLatch latch){
        this.name = name;
        this.timeToStart = timeToStart;
        this.latch = latch;
    }

    @Override
    public void run() {
        try {
            Thread.sleep(timeToStart);
        } catch (InterruptedException ex) {
            Logger.getLogger(Service.class.getName()).log(Level.SEVERE, null, ex);
        }
        System.out.println( name + " is Up");
        latch.countDown(); //reduce count of CountDownLatch by 1
    }

}

Output:
CacheService is Up
All services are up, Application is starting now

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在Java中:如何让线程监视另一个线程? - In Java: how can I make thread watch over another thread? Java Thread,如何让一个线程始终先停止或结束? - Java Thread, how can I make one thread always stop or end first? 如何确保在 java 中一个线程始终先于其他线程运行? 给定两个线程。 我需要确保线程 1 始终领先于线程 2 - How do I ensure that one thread always run ahead of other in java? Given two threads. I need to make sure that Thread 1 always leads Thread 2 我可以在java中的线程中运行一个线程吗? - Can I run a thread within a thread in java? 如何在java中将主线程作为守护线程? - How can i make the main Thread as Daemon Thread in java? 我如何确定守护程序线程始终在Java中运行? - How can I be sure a daemon thread is always running, in Java? 如何使当前线程在继续执行之前等待另一个线程完成? - How do I make the current thread wait for another thread to finish before proceeding? 在继续使用Java中的另一个线程之前,如何等待线程做某事? - How to wait for a thread to do something before continuing on another thread in Java? 如何在Java / Android中另一个线程启动之前等待线程完成? - How to wait for a thread to finish before another thread starts in Java/Android? 如何确保一个线程在另一个线程之前启动? - How do I ensure that a thread is started before another thread?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM