简体   繁体   English

如何在Java中创建这三个线程

[英]How to create these three threads in Java

I am new to threads, and I don't know much about them, however I am struggling with creating them mainly. 我是线程的新手,对线程的了解也不多,但是我主要是在创建线程方面苦苦挣扎。

I created a GUI program that repeatedly sorts a randomly generated array of ints using either selection sort, insertion sort, or merge sort. 我创建了一个GUI程序,该程序使用选择排序,插入排序或合并排序对随机生成的整数数组进行重复排序。 Each sort operates on a list whose size is raised by a power of 2. Upon completion of each sort, the number of elements sorted and the number of milliseconds it took is displayed. 每种排序在一个列表上进行操作,该列表的大小以2的幂增加。完成每种排序后,将显示排序的元素数及其花费的毫秒数。

I have 3 classes already done, they are Merge, selection, and insertion. 我已经完成了3个课程,分别是Merge,selection和insert。

My Merge sort is working correctly, however I am still having trouble with the selection and insertion. 我的合并排序工作正常,但是选择和插入仍然遇到问题。 I'm not sure if my 'if' and 'else' statements are incorrect, or if the threads themselves are wrong, but I am struggling with them. 我不确定我的'if'和'else'语句是否错误,或者线程本身是否错误,但是我正在努力解决它们。

Here's what I have in my Main class. 这是我在班上的东西。

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.swing.*;
import javax.swing.border.EmptyBorder;

public class Sorter extends JFrame
{
private static final long serialVersionUID = 1L;
private static final int WIDTH = 400;
private static final int HEIGHT = 300;

public static final String SELECTION_SORT_TEXT = "Selection Sort";
public static final String INSERTION_SORT_TEXT = "Insertion Sort";
public static final String MERGE_SORT_TEXT = "Merge Sort";

private JComboBox sortingAlgorithms;
private JTextArea display;
private JButton sortButton;
private JPanel panel;
private JLabel loadingIcon;
private JLabel sort;
private String[] options = {SELECTION_SORT_TEXT, INSERTION_SORT_TEXT, MERGE_SORT_TEXT};

public Sorter()
{
    setTitle("Sorter");
    setSize(WIDTH, HEIGHT);
    setLayout(new BorderLayout());
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    createContents();
    setVisible(true);
}
private void createContents()
{
    //TODO: Implement

    this.panel = new JPanel(new FlowLayout());
    this.display = new JTextArea();
    this.loadingIcon = new JLabel(new ImageIcon("loading.gif"));
    this.sort = new JLabel("Sorting Algorithm");
    this.sortButton = new JButton("Sort");
    this.sortingAlgorithms = new JComboBox<>(options);
    loadingIcon.setSize(25,25);

    display.setBorder(new EmptyBorder(10,10,10,10));

    panel.add(sort);
    panel.add(sortingAlgorithms);
    panel.add(sortButton);
    panel.add(loadingIcon);

    sortButton.addActionListener(new SortButtonListener());

    loadingIcon.setVisible(false);
    display.setEnabled(false);

    setLayout(new BorderLayout());
    add(panel, BorderLayout.NORTH);
    add(display, BorderLayout.CENTER);
}

private class SortButtonListener implements ActionListener
{
    private int[] arr;
    private SortRunnable sr;

    public void actionPerformed(ActionEvent e)
    {
        sr.run();
        ExecutorService es = Executors.newSingleThreadExecutor();
        //TODO: Finish Implementation
        if(e.getSource() == sortButton)
        {
            sortingAlgorithms.setEnabled(false);
            sortButton.setEnabled(false);
            loadingIcon.setVisible(true);
            display.setText("N\t\tRuntime (ms)");             
        }
        arr = new int [2000];
        for(int i = 0; i <= 8; i++)
        {
            arr = new int [(int) Math.pow(2, i) * 1000];
            fillArr();
            sr = new SortRunnable((String) sortingAlgorithms.getSelectedItem(), arr, Sorter.this);
            es.execute(sr);
        }
        Thread sortContext = new Thread(new SortRunnable((String) 
        sortingAlgorithms.getSelectedItem(), arr, Sorter.this));
        sortContext.start();
        es.shutdown();
    }
    /*
    These values are powers of 2 from 0 to 8, times 1000.
     */
    private void fillArr()
    {
        Random r = new Random();
        int n = 0;
        for(int i=0; i<arr.length; ++i)
        {
            arr[i] = r.nextInt();
        }
    }
}
/*
The displayResult method is responsible for adding the provided sort runtime information to
the display. It should also check to see if the final sort runtime information is present. If so,
it should hide the loading gif and enable the JComboBox and sort button.
 */
public synchronized void displayResult(int n, long runtime)
{
    //TODO: Implement
    display.append("\n" + n + "\t\t" + runtime);
}

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

I am not too concerned with what's above. 我不太担心上面的内容。 I am more concerned on how to create my thread in my SortRunnable class which these threads are created. 我更关心如何在创建这些线程的SortRunnable类中创建线程。 Here is what is expected from this class. 这是本堂课的期望。

This class contains the code used to time and execute the selected sort. 此类包含用于计时和执行所选排序的代码。

• You can find the difference between calls to System.currentTimeMillis() at the start end end of the sort to get its runtime. •您可以在排序的开始末尾找到对System.currentTimeMillis()的调用之间的差异,以获取其运行时间。

• Call "Thread.yield()" in the Runnable before the search is executed to ensure that the GUI thread has the priority required to update its display as needed. •在执行搜索之前,在Runnable中调用“ Thread.yield()”,以确保GUI线程具有根据需要更新其显示所需的优先级。

• When the sort has finished, the display should be updated in the GUI thread. •排序完成后,应该在GUI线程中更新显示。 This can be accomplished by calling the "displayResult" method on the Sorter reference. 这可以通过在Sorter引用上调用“ displayResult”方法来完成。 This call should occur within the Runnable object's run method, passed as an argument to SwingUtilities invokeLater method, as in: 该调用应在Runnable对象的run方法中进行,并作为参数传递给SwingUtilities invokeLater方法,如下所示:

 SwingUtilities.invokeLater(new Runnable() 
 {
 @Override
 public void run() 
 {
   //call Sorter's displayResult method here
 }
 });

Here is my code in there that I need help in. 这是我需要帮助的代码。

import javax.swing.*;

public class SortRunnable implements Runnable
{

    private String sortingAlgorithm;
    private int[] arr;
    private Sorter sorter;

    public SortRunnable(String sortingAlgorithm, int[] arr, Sorter sorter)
    {
        this.sortingAlgorithm = sortingAlgorithm;
        this.arr = arr;
        this.sorter = sorter;
    }
    @Override
    public void run()
    {
        Thread.yield();
        if(sortingAlgorithm.equals(sorter.MERGE_SORT_TEXT))
        {
            MergeSort.mergeSort(arr);
        }
        Thread.yield();
        if(sortingAlgorithm.equals(sorter.SELECTION_SORT_TEXT))
        {
            SelectionSort.sort(arr);
        }
        Thread.yield();
        if(sortingAlgorithm.equals(sorter.INSERTION_SORT_TEXT))
        {
            InsertionSort.sort(arr);
        }
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                Thread.yield();
                sorter.displayResult(arr.length, System.currentTimeMillis());
            //call Sorter's displayResult method here
            }
        });
    }

}

I just need help with the Insertion and Selection thread. 我只需要有关“插入和选择”线程的帮助。 Thank you! 谢谢! If you would like their individual classes so you can see what's inside of them let me know. 如果您想要他们的个人班级,这样您就可以了解他们的内心世界。

SwingUtilities.invokeLater places the request into in the Swing's event queue to be processed "at some point in the future". SwingUtilities.invokeLater将请求放入Swing的事件队列中,以“在将来某个时候”进行处理。 The Runnable is dequeued and executed within the context of the Event Dispatching Thread, meaning your sort is running in the same thread as the UI and will block it until it has completed. Runnable在Event Dispatching Thread的上下文中出队并执行,这意味着您的排序与UI在同一线程中运行,并将阻止它直到完成。

Now, here is where things get really complicated. 现在,事情变得非常复杂。 Swing is NOT thread safe (meaning you shouldn't update the UI from outside of the Event Dispatching Thread context)and is single threaded, meaning any long running or blocking operations will prevent the UI from been updated. Swing不是线程安全的(这意味着您不应从事件调度线程上下文之外更新UI),并且它是单线程的,这意味着任何长时间运行或阻塞的操作都将阻止UI的更新。

The "long" answer is, use a SwingWorker , which is designed for this job. “长”答案是使用为此作业设计的SwingWorker However, you can continue using your code, but it's a little more messy. 但是,您可以继续使用您的代码,但是有点混乱。

You need to capture some more details, like when the sort was started and when the sort ended. 您需要捕获更多详细信息,例如何时开始排序以及何时结束排序。 You then need to calculate the difference between these two points in time as milliseconds. 然后,您需要计算这两个时间点之间的差(以毫秒为单位)。

There are lots of ways you "might" do this, but since Java now sports a nice new date/time API, you might as well start making use of it. 您有很多“可能”执行此操作的方法,但是由于Java现在使用了不错的新日期/时间API,因此您不妨开始使用它。

This information is then passed back to the UI, maybe something like... 然后,此信息将传递回用户界面,可能类似于...

public class SortRunnable implements Runnable
{

    private String sortingAlgorithm;
    private int[] arr;
    private Sorter sorter;

    public SortRunnable(String sortingAlgorithm, int[] arr, Sorter sorter)
    {
        this.sortingAlgorithm = sortingAlgorithm;
        this.arr = arr;
        this.sorter = sorter;
    }
    @Override
    public void run()
    {
        LocalDateTime startTime = LocalDateTime.now();
        MergeSort.mergeSort(arr);
        LocalDateTime endTime = LocalDateTime.now();
        long diff = ChronoUnit.MILLIS.between(startTime, endTime)
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                sorter.displayResult(arr.length, diff);
            }
        });
    }

}

Okay, the next problem, is you're not making use of the ExecutorService . 好的,下一个问题是您没有使用ExecutorService

First, it really should be an instance field, as you don't need to keep creating more instances of it. 首先,它实际上应该是一个实例字段,因为您无需继续创建它的更多实例。

Second, your logic is all over the place, basically you want to... 其次,您的逻辑无处不在,基本上您想...

  1. Create an instance of the Sorter 创建Sorter的实例
  2. Fill the array 填充数组
  3. Create an instance of SortRunnable 创建SortRunnable的实例
  4. Submit SortRunnable to the ExecutorService so it can be executed... SortRunnable提交给ExecutorService以便可以执行...

Maybe something more like... 也许更像是...

private ExecutorService es = Executors.newSingleThreadExecutor();
public void actionPerformed(ActionEvent e)
{
    fillArr();
    Sorter sorter = null;
    String algorthim = null;
    if(e.getSource() == options[0])
    {
        // create the instance of Sorter to be used...
        sorter = ...
        algorthim = ...
    }
    if(e.getSource() == options[1])
    {
        // create the instance of Sorter to be used...
        sorter = ...
        algorthim = ...
    }
    if(e.getSource() == options[2])
    {
        // create the instance of Sorter to be used...
        sorter = ...
        algorthim = ...
    }
    if (sorter != null) {
        SortRunnable sr = new SortRunnable(algorthim, arr, sorter)
        es.submit(sr);
    }

My solution on creating these threads go as following: 我创建这些线程的解决方案如下:

In the sortRunnable class: 在sortRunnable类中:

public void run()
    {
        long store = System.currentTimeMillis();
        if(sortingAlgorithm.equals(sorter.MERGE_SORT_TEXT))
        {
            MergeSort.mergeSort(arr);
        }
        if(sortingAlgorithm.equals(sorter.SELECTION_SORT_TEXT))
        {
            SelectionSort.sort(arr);
        }
        if(sortingAlgorithm.equals(sorter.INSERTION_SORT_TEXT))
        {
            InsertionSort.sort(arr);
        }
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                sorter.displayResult(arr.length, System.currentTimeMillis()-store);
            //call Sorter's displayResult method here
            }
        });
    }

That's where I created my threads. 那就是我创建线程的地方。

On my other class, I put them in as following: 在另一堂课上,我将它们放在以下位置:

private class SortButtonListener implements ActionListener
{
    private int[] arr;
    private SortRunnable sr;

    public void actionPerformed(ActionEvent e)
    {
        ExecutorService es = Executors.newSingleThreadExecutor();
        //TODO: Finish Implementation
        if(e.getSource() == sortButton)
        {
            sortingAlgorithms.setEnabled(false);
            sortButton.setEnabled(false);
            loadingIcon.setVisible(true);
            display.setText("N\t\tRuntime (ms)");
        }
        arr = new int [2000];
        for(int i = 0; i <= 8; i++)
        {
            arr = new int [(int) Math.pow(2, i) * 1000];
            fillArr();
            sr = new SortRunnable((String) sortingAlgorithms.getSelectedItem(), arr, Sorter.this);
            es.execute(sr);
        }
        es.shutdown();
    }
    private void fillArr()
    {
        Random r = new Random();
        for(int i=0; i<arr.length; ++i)
        {
            arr[i] = r.nextInt();
        }
    }
}

Which the other methods was asked to do, but that's where I put in my threads. 要求其他方法执行哪些操作,但这就是我放入线程的地方。

Thread sortContext = new Thread(new SortRunnable(*whatever args you need*));
sortContext.start();

should do the trick unless you try to update the ui from the new thread. 除非您尝试从新线程更新ui,否则应该可以解决问题。

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM