简体   繁体   中英

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. 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.

I have 3 classes already done, they are Merge, selection, and insertion.

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.

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. 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.

• 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.

• When the sort has finished, the display should be updated in the GUI thread. This can be accomplished by calling the "displayResult" method on the Sorter reference. This call should occur within the Runnable object's run method, passed as an argument to SwingUtilities invokeLater method, as in:

 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". 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.

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.

The "long" answer is, use a SwingWorker , which is designed for this job. 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.

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 .

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
  2. Fill the array
  3. Create an instance of SortRunnable
  4. Submit SortRunnable to the ExecutorService so it can be executed...

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:

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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