Java 生产者-消费者多线程同步问题

Java 生产者-消费者多线程同步问题,java,multithreading,arraylist,synchronization,Java,Multithreading,Arraylist,Synchronization,大家好(第一篇帖子) 首先让我说,我对Java编程还是比较陌生的(C++是我的强项) 如果这个问题已经得到了回答,请给我指出正确的方向,但我的搜索技能还没有产生我想要的。我遇到的问题是在消费者线程之间同步,而不是在生产者/消费者之间同步 我的任务是从生产者线程中查找质数候选,而不是使用多个消费者线程检查每个候选的有效性: 使用多个线程,1个生产者线程将“候选对象”放入名为prime_候选对象的arraylist(必须是arraylist),消费者从arraylist中获取并检查 消费者检查是否

大家好(第一篇帖子)

首先让我说,我对Java编程还是比较陌生的(C++是我的强项)

如果这个问题已经得到了回答,请给我指出正确的方向,但我的搜索技能还没有产生我想要的。我遇到的问题是在消费者线程之间同步,而不是在生产者/消费者之间同步

我的任务是从生产者线程中查找质数候选,而不是使用多个消费者线程检查每个候选的有效性:

  • 使用多个线程,1个生产者线程将“候选对象”放入名为prime_候选对象的arraylist(必须是arraylist),消费者从arraylist中获取并检查

  • 消费者检查是否为素数,然后将素数放入自己的arraylist素数列表中

  • 60秒后,prime_列表写入文件并继续

我已成功地将prime_候选线程与使用者(检查)线程同步。但我一辈子都搞不懂如何同步消费线程生成的ArrayList。他们都自己制作,使用我从生产者/消费者那里使用的同步方法不起作用

生产者线程

import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Date;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;


public class GenerateThread implements Runnable{

// MAIN ARRAY LIST THAT STORES THE NUMBERS WHICH COULD BE CONSIDERED PRIME CANDIDATES
private final ArrayList<PrimeCandidate> prime_candidates = new ArrayList();

private boolean alive = true;   // MAIN VARIABLE THAT WILL CONTINUE TO RUN THE THREAD 
private boolean toggle = true;  // VARIABLE THAT PAUSES THE PRODUCER

// START: FOR PANEL LAYOUT //
JPanel genPanel = new JPanel();

JPanel lastPane = new JPanel();
JLabel lastOutput = new JLabel();

JPanel queuePane = new JPanel();
JLabel queueOutput = new JLabel();

JLabel headLabel = new JLabel("Generate Thread");
JLabel lastLabel = new JLabel("Last");
JLabel queueLabel = new JLabel("Queue");

JButton pauseButton = new JButton("Pause");
JButton terminateButton = new JButton("Terminate");
// END: FOR PANEL LAYOUT //

// DEFAULT CONSTRUCTOR, DOESN'T REALLY DO MUCH
GenerateThread(){ System.out.println("Creating Generator");}

public JPanel createPanel()
{
    // TO SET THE BLACK BORDER AROUND THE PANELS HOLDING CURRENT SIZE AND 
    // PRIME CANDIDATE
    lastPane.setBorder(BorderFactory.createLineBorder(Color.black));
    queuePane.setBorder(BorderFactory.createLineBorder(Color.black));

    // ADD LISTENER TO TERMINATE THREAD
    terminateButton.addActionListener(new terminateListener());

    // ADD LISTENER TO PAUSE THREAD
    pauseButton.addActionListener(new pauseListener());

    lastPane.add(lastOutput);
    queuePane.add(queueOutput);

    genPanel.add(headLabel);
    genPanel.add(lastLabel);
    genPanel.add(lastPane);
    genPanel.add(queueLabel);
    genPanel.add(queuePane);
    genPanel.add(pauseButton);
    genPanel.add(terminateButton);

    return genPanel;
}


@Override
public void run() 
{
    long i = 3;
    while(alive)
    {
        if(toggle)
        {
            if(i % 2 == 1)
                if(!TestForPrime.isDividableBy3(BigInteger.valueOf(i)))
                {
                    addToArrayList(BigInteger.valueOf(i));
                    lastOutput.setText(BigInteger.valueOf(i).toString());
                    queueOutput.setText(BigInteger.valueOf(prime_candidates.size()).toString());
                }
            i++;
        }
        if(!toggle)continueNotifying();
    }
    while(!alive){continueNotifying();}
}

// ADDS NEW ITEM TO ARRAYLIST AND NOTIFYS ALL THREADS DEPENDENT ON ARRAYLIST
public synchronized void addToArrayList(BigInteger b)
{
        prime_candidates.add(new PrimeCandidate(b, new Date()));
        notify();
}

// CONTINUES NOTIFYING OTHER THREADS WHEN PAUSED OR TERMINATED SINCE THEY WILL
// NOT RUN UNLESS THEY HAVE BEEN GIVEN THE 'GO AHEAD' (NOTIFY())
public synchronized void continueNotifying()
{
    queueOutput.setText(BigInteger.valueOf(prime_candidates.size()).toString());
    notify();
}

// USED BY THE OTHER THREADS TO GET ITEMS FROM THE ARRAY LIST, THREADS DELETE
// THE VARIABLE THAT THEY GRAB, ESSENTIALLY CUTTING THE ARRAY LIST DOWN EVERY
// TIME
public synchronized PrimeCandidate getFromArrayList() throws InterruptedException 
{
      wait(); //Keeps thread from adding more to list while others are grabbing it

      PrimeCandidate returnCandidate = new PrimeCandidate(prime_candidates.get(0));

      prime_candidates.remove(0);

      return returnCandidate;
}

// LISTENER THAT WILL KILL THE THREAD PRIME CANDIDATE PRODUCER
// ALSO GREYS OUT BOTH BUTTONS TO SHOW THREAD IS DEAD
class terminateListener implements ActionListener
{
    @Override
    public void actionPerformed(ActionEvent e)
    { 
        terminateButton.setEnabled(false);
        pauseButton.setEnabled(false);
        alive = false;
    }
}

// LISTENER THAT WILL TEMPORARILY STOP THE PRODUCER
class pauseListener implements ActionListener
{
    @Override
    public void actionPerformed(ActionEvent e) 
    { 
        if(toggle)
            pauseButton.setText("Start");
        if(!toggle)
            pauseButton.setText("Pause");
        toggle = !toggle;
    }
}
}
导入java.awt.Color;
导入java.awt.event.ActionEvent;
导入java.awt.event.ActionListener;
导入java.math.biginger;
导入java.util.ArrayList;
导入java.util.Date;
导入javax.swing.BorderFactory;
导入javax.swing.JButton;
导入javax.swing.JLabel;
导入javax.swing.JPanel;
公共类GenerateThread实现可运行{
//主数组列表,存储可被视为主要候选的数字
私有最终ArrayList素数_候选者=新ArrayList();
private boolean alive=true;//将继续运行线程的主变量
private boolean toggle=true;//暂停生产者的变量
//开始:用于面板布局//
JPanel genPanel=新的JPanel();
JPanel lastPane=新的JPanel();
JLabel lastOutput=新的JLabel();
JPanel queuePane=新的JPanel();
JLabel queueOutput=新的JLabel();
JLabel hightabel=新JLabel(“生成线程”);
JLabel lastLabel=新的JLabel(“最后”);
JLabel queueLabel=新的JLabel(“队列”);
JButton pauseButton=新JButton(“暂停”);
JButton terminateButton=新JButton(“终止”);
//结束:用于面板布局//
//默认构造函数,实际上做的不多
GenerateThread(){System.out.println(“创建生成器”);}
公共JPanel createPanel()
{
//在保持当前尺寸和尺寸的面板周围设置黑色边框的步骤
//主要候选人
setboorder(BorderFactory.createLineBorder(Color.black));
setboorder(BorderFactory.createLineBorder(Color.black));
//添加侦听器以终止线程
addActionListener(新的terminateListener());
//将侦听器添加到暂停线程
addActionListener(新的pauseListener());
添加(lastOutput);
queuePane.add(queueOutput);
genPanel.add(海岬标);
genPanel.add(lastLabel);
genPanel.add(lastPane);
genPanel.add(队列标签);
添加(队列窗格);
genPanel.add(暂停按钮);
genPanel.add(终止按钮);
返回面板;
}
@凌驾
公开募捐
{
长i=3;
(活着时)
{
如果(切换)
{
如果(i%2==1)
如果(!TestForPrime.isDividableBy3(BigInteger.valueOf(i)))
{
addToArrayList(BigInteger.valueOf(i));
setText(biginger.valueOf(i.toString());
queueOutput.setText(biginger.valueOf(prime_candidates.size()).toString());
}
i++;
}
如果(!toggle)continueNotifying();
}
当(!活着){继续化();}
}
//将新项添加到ARRAYLIST并通知所有依赖于ARRAYLIST的线程
公共同步的void addToArrayList(BigInteger b)
{
prime_候选者。添加(新prime候选者(b,新日期());
通知();
}
//暂停或终止时继续通知其他线程,因为它们将
//除非已向其发出“继续”(NOTIFY())命令,否则不运行
公共同步的void continuentifing()
{
queueOutput.setText(biginger.valueOf(prime_candidates.size()).toString());
通知();
}
//其他线程用于从数组列表中获取项,线程删除
//它们获取的变量,本质上是每一个
//时间
公共同步PrimeCandidate getFromArrayList()引发InterruptedException
{
wait();//防止线程在其他线程抓取时向列表中添加更多内容
PrimeCandidate returnCandidate=新的PrimeCandidate(prime_candidates.get(0));
素数候选。删除(0);
返回候选人;
}
//将杀死线程主要候选生产者的侦听器
//同时,两个按钮都变灰,以显示线程已停止
类terminateListener实现ActionListener
{
@凌驾
已执行的公共无效操作(操作事件e)
{ 
terminateButton.setEnabled(假);
pauseButton.setEnabled(false);
活着=假;
}
}
//将临时停止生产者的侦听器
类pauseListener实现ActionListener
{
@凌驾
已执行的公共无效操作(操作事件e)
{ 
如果(切换)
setText(“开始”);
如果(!切换)
pauseButton.setText(“暂停”);
切换=!切换;
}
}
}
消费者线程

import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedWriter;  
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Date;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;

public class CheckThread  implements Runnable{

private final GenerateThread generated;
private ArrayList<Primes> prime_list = new ArrayList();
//private CopyOnWriteArrayList<Primes> prime_list = new CopyOnWriteArrayList();
private final String threadName;
private boolean alive = true;
private boolean toggle = true;
private Date timeFetched;
private Date timeFound;
private Primes currentPrime;

// START: FOR PANEL LAYOUT //
JPanel genPanel = new JPanel();

JPanel lastPane = new JPanel();
JLabel lastOutput = new JLabel();

JPanel queuePane = new JPanel();
JLabel queueOutput = new JLabel();

JLabel headLabel = new JLabel("Generate Thread");
JLabel lastLabel = new JLabel("Last");
JLabel queueLabel = new JLabel("In Work");

JButton pauseButton = new JButton("Pause");
JButton terminateButton = new JButton("Terminate");
// END: FOR PANEL LAYOUT //

CheckThread(GenerateThread gen, String name, int priority)
{
    generated = gen;
    threadName = name;
    headLabel.setText(name);
    System.out.println("Creating | " + name);

    if(priority == 0)
    {
       System.out.println(name + " Is writing thread");
        final Timer t = new Timer(10000, new writeToFileTimer());
        t.start();
    }
}

public JPanel createPanel()
{
   lastPane.setBorder(BorderFactory.createLineBorder(Color.black));
   lastPane.setMinimumSize(new Dimension(200,100));
   queuePane.setBorder(BorderFactory.createLineBorder(Color.black));


   terminateButton.addActionListener(new terminateListener());

   pauseButton.addActionListener(new pauseListener());

   lastPane.add(lastOutput);
   queuePane.add(queueOutput);

   genPanel.add(headLabel);
   genPanel.add(lastLabel);
   genPanel.add(lastPane);
   genPanel.add(queueLabel);
   genPanel.add(queuePane);
   genPanel.add(pauseButton);
   genPanel.add(terminateButton);

   lastOutput.setIgnoreRepaint(true);
   return genPanel;
}
 class writeToFileTimer implements ActionListener
 {
    @Override
    public void actionPerformed(ActionEvent event)
    {
       try{ writeToFile();}catch (InterruptedException e) { System.out.println("WTF");}
    }
 }

@Override
public void run() 
{
    while(alive)
    {
        try 
        {
            if(toggle)
            {
                PrimeCandidate recieved = new PrimeCandidate(generated.getFromArrayList());
                timeFetched = new Date();
                //queueOutput.setText(recieved.getCandidate().toString());
                if(TestForPrime.isPrime(recieved.getCandidate()))
                {
                    lastOutput.setText(recieved.getCandidate().toString());
                    timeFound = new Date();
                    String temp = "" + prime_list.size();
                    queueOutput.setText(temp);
                    addToArrayList(new Primes(recieved.getCandidate(),recieved.getTimeStamp(), timeFetched));
                }
            }
        } catch (InterruptedException e) {}
    }
}

class terminateListener implements ActionListener
{
    @Override
    public void actionPerformed(ActionEvent e) 
    { 
        terminateButton.setEnabled(false);
        pauseButton.setEnabled(false);
        alive = false;
    }
}

class pauseListener implements ActionListener
{
    @Override
    public void actionPerformed(ActionEvent e) 
    { 
        if(toggle)
            pauseButton.setText("Start");
        if(!toggle)
            pauseButton.setText("Pause");
        toggle = !toggle;
    }
}

// ADDS NEW ITEM TO ARRAYLIST AND NOTIFYS ALL THREADS DEPENDENT ON ARRAYLIST 
public synchronized void addToArrayList(Primes primeFound)
{
        prime_list.add(primeFound);
}

// USED BY THE OTHER THREADS TO GET ITEMS FROM THE ARRAY LIST, THREADS DELETE
// THE VARIABLE THAT THEY GRAB, ESSENTIALLY CUTTING THE ARRAY LIST DOWN EVERY
// TIME
public synchronized void writeToFile() throws InterruptedException
{
    wait(); 
    try 
    {
        File statText = new File("prime_numbers.txt");

        FileOutputStream is = new FileOutputStream(statText);

        OutputStreamWriter osw = new OutputStreamWriter(is);    

        Writer writ = new BufferedWriter(osw);
        while(!prime_list.isEmpty())
        {
            writ.append(prime_list.get(0).toString());
            prime_list.remove(0);
        }
        writ.close();
        headLabel.setText(threadName);

    } catch (IOException e) {System.err.println(" failed to write to Test.txt");}
    notify();
}   
}
导入java.awt.Color;
导入java.awt.Dimension;
导入java.awt.event.ActionEvent;
导入java.awt.event.ActionListener;
导入java.io.BufferedWriter;
导入java.io.File;
导入java.io.FileOutputStream;
导入java.io.IOException;
导入java.io.OutputStreamWriter;
导入java.io.Writer;
导入java.util.ArrayList;
导入java.util.Date;
导入javax.swing.BorderFactory;
重要的
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedWriter;  
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Date;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;

public class CheckThread  implements Runnable{

private final GenerateThread generated;
private static ArrayList<Primes> prime_list = new ArrayList();
//private CopyOnWriteArrayList<Primes> prime_list = new CopyOnWriteArrayList();
private final String threadName;
private boolean alive = true;
private boolean toggle = true;
private Date timeFetched;
private Date timeFound;
private Primes currentPrime;

// START: FOR PANEL LAYOUT //
JPanel genPanel = new JPanel();

JPanel lastPane = new JPanel();
JLabel lastOutput = new JLabel();

JPanel queuePane = new JPanel();
JLabel queueOutput = new JLabel();

JLabel headLabel = new JLabel("Generate Thread");
JLabel lastLabel = new JLabel("Last");
JLabel queueLabel = new JLabel("In Work");

JButton pauseButton = new JButton("Pause");
JButton terminateButton = new JButton("Terminate");
// END: FOR PANEL LAYOUT //

CheckThread(GenerateThread gen, String name, int priority)
{
    generated = gen;
    threadName = name;
    headLabel.setText(name);
    System.out.println("Creating | " + name);

    if(priority == 0)
    {
       System.out.println(name + " Is writing thread");
        final Timer t = new Timer(10000, new writeToFileTimer());
        t.start();
    }
}

public JPanel createPanel()
{
   lastPane.setBorder(BorderFactory.createLineBorder(Color.black));
   lastPane.setMinimumSize(new Dimension(200,100));
   queuePane.setBorder(BorderFactory.createLineBorder(Color.black));


   terminateButton.addActionListener(new terminateListener());

   pauseButton.addActionListener(new pauseListener());

   lastPane.add(lastOutput);
   queuePane.add(queueOutput);

   genPanel.add(headLabel);
   genPanel.add(lastLabel);
   genPanel.add(lastPane);
   genPanel.add(queueLabel);
   genPanel.add(queuePane);
   genPanel.add(pauseButton);
   genPanel.add(terminateButton);

   lastOutput.setIgnoreRepaint(true);
   return genPanel;
}
 class writeToFileTimer implements ActionListener
 {
    @Override
    public void actionPerformed(ActionEvent event)
    {
       try{ writeToFile();}catch (InterruptedException e) { System.out.println("WTF");}
    }
 }

@Override
public void run() 
{
    while(alive)
    {
        try 
        {
            if(toggle)
            {
                PrimeCandidate recieved = new PrimeCandidate(generated.getFromArrayList());
                timeFetched = new Date();
                //queueOutput.setText(recieved.getCandidate().toString());
                if(TestForPrime.isPrime(recieved.getCandidate()))
                {
                    lastOutput.setText(recieved.getCandidate().toString());
                    timeFound = new Date();
                    String temp = "" + prime_list.size();
                    queueOutput.setText(temp);
                    addToArrayList(new Primes(recieved.getCandidate(),recieved.getTimeStamp(), timeFetched));
                }
            }
        } catch (InterruptedException e) {}
    }
}

class terminateListener implements ActionListener
{
    @Override
    public void actionPerformed(ActionEvent e) 
    { 
        terminateButton.setEnabled(false);
        pauseButton.setEnabled(false);
        alive = false;
    }
}

class pauseListener implements ActionListener
{
    @Override
    public void actionPerformed(ActionEvent e) 
    { 
        if(toggle)
            pauseButton.setText("Start");
        if(!toggle)
            pauseButton.setText("Pause");
        toggle = !toggle;
    }
}

// ADDS NEW ITEM TO ARRAYLIST AND NOTIFYS ALL THREADS DEPENDENT ON ARRAYLIST 
public static void addToArrayList(Primes primeFound)
{
   synchronized(prime_list) { // Added this
       prime_list.add(primeFound);
   }
}

// USED BY THE OTHER THREADS TO GET ITEMS FROM THE ARRAY LIST, THREADS DELETE
// THE VARIABLE THAT THEY GRAB, ESSENTIALLY CUTTING THE ARRAY LIST DOWN EVERY
// TIME
public static void writeToFile() throws InterruptedException
{
    synchronized(prime_list) { // Added this
    try 
    {
        File statText = new File("prime_numbers.txt");

        FileOutputStream is = new FileOutputStream(statText);

        OutputStreamWriter osw = new OutputStreamWriter(is);    

        Writer writ = new BufferedWriter(osw);
        for(int i=0;i<prime_list.size();i++) {
            writ.append(prime_list.get(i));
        }
        prime_list.clear();
        writ.close();
        headLabel.setText(threadName);

    } catch (IOException e) {System.err.println(" failed to write to Test.txt");}
    }
}   
}