使用notify从其状态唤醒一个线程

时间:2012-01-17 01:15:56

标签: java multithreading concurrency

我很绝望......我整天都在一个程序上工作,但我没有解决我关于线程功能的问题。请帮助我。

我有这个类是一个通用的Item.My问题是当这个对象进入wait()时它就不会再唤醒了,即使我在方法putItemToWork()上调用同一个对象。我会知道如果关于cuncurrency的代码有错误,因为我真的不明白我犯错误的地方......

项目类

import java.io.*;

public class Item implements Serializable
{
private String id;
private String category;
private String machine;
private boolean isWorked;

private String mchTemp = null; 

public Item(String id,String category,String machine,boolean isWorked)
{
    this.id = id;
    this.category = category;
    this.machine = machine;
    this.isWorked = isWorked;
}

public synchronized void putItemToWork(String id_machine)
{    
    try
        {
            System.out.println("Working the item...");
            Thread.sleep((long)(1+Math.random()*10000));
        }
        catch(InterruptedException ie) {ie.printStackTrace(); }

            mchTemp = id_machine;        
    isWorked = true;
    notify();
}

public synchronized String getWorkedItem()
{
    if(mchTemp == null)
    {
        try
        {   
            wait();
        }
        catch(InterruptedException ie) {ie.printStackTrace(); }
    }

    return mchTemp;
}

public String getId()
{
    return this.id;
}

public String getCategory()
{
    return this.category;
}

public String getMachine()
{
    return this.machine;
}

public boolean isWorked()
{
    return this.isWorked;
}
}
}

ServerMultiThread

import java.io.*;
import java.util.*;
import java.net.*;
import javax.swing.SwingUtilities;
import javax.swing.JTextArea;

public class ServerMultiThread implements Runnable
{   
Socket socket;
private ServerSocket serverSocket;
private LinkedList<Item> itemsList;
private LinkedList<Machine> machinesList;
private static final boolean listening = true;
private JTextArea output;

public ServerMultiThread(LinkedList<Item> itemsList,LinkedList<Machine> machinesList,JTextArea output)
{
    this.itemsList = itemsList;
    this.machinesList = machinesList;

    this.output = output;

    try
    {
        this.serverSocket = new ServerSocket(8090);
    }
    catch(IOException ioe){ioe.printStackTrace(); }

    new Thread(this, "Server").start();
}

@Override
public void run()
{
    Item itemTemp = null;

    SwingUtilities.invokeLater(new Runnable(){@Override public void run(){output.append("Server in run!\n");}});

    while(listening)
    {

        try
        {
            SwingUtilities.invokeLater(new Runnable(){public void run(){output.append("Waiting for incoming connection...\n");}});

            socket = serverSocket.accept();

            SwingUtilities.invokeLater(new Runnable(){@Override public void run(){output.append("Connected to: "+socket.getInetAddress()+":"+socket.getPort()+"!\n");}});

            ObjectOutputStream ous = new ObjectOutputStream(socket.getOutputStream());

            synchronized(itemsList)
            {
                for(Item item : itemsList)
                {
                    if(!item.isWorked())
                    {
                        itemTemp = item;
                        break;
                    }
                }

                new ItemHandler(itemTemp,ous,output);
            }

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

ItemHandler

import java.io.*;
import java.util.LinkedList;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;

public class ItemHandler implements Runnable
{
String id_machine;
private Item item;
private ObjectOutputStream ous;
//private ObjectInputStream ois;
private JTextArea output;

public ItemHandler(Item item,ObjectOutputStream ous,JTextArea output)
{
    this.item = item;
    this.ous = ous;
    //this.ois = ois;
    this.output = output;

    new Thread(this).start();
}

@Override
public void run()
{
    try
    {
        ous.writeObject(item);                    

        SwingUtilities.invokeLater(new Runnable(){public void run(){output.append("Item Handler "+item.getId()+ " in run!\n");}});

        id_machine = item.getWorkedItem();

        SwingUtilities.invokeLater(new Runnable(){public void run(){output.append("The item "+item.getId()+" was correctly worked by "+id_machine);}});

        //System.out.println("The item "+workedItem.getId()+" was correctly worked by "+workedItem.getMachine());
    }
    catch(IOException ioe){ioe.printStackTrace();}
}
}

MachineApp

import java.io.*;
import java.net.*;

public class MachineApp 
{
private Socket socket;
private String id_machine;

public MachineApp(String id_machine)
{
    this.id_machine = id_machine;

    try
    {
        this.socket = new Socket("localhost",8090);

        System.out.println("Estabilished connection to main server!");
    }
    catch(UnknownHostException uhe) {uhe.printStackTrace();}
    catch(IOException ioe) {ioe.printStackTrace(); }

    execution();
}

private void execution()
{
    try
    {
        //ObjectOutputStream ous = new ObjectOutputStream(socket.getOutputStream());    
        ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());          

        Item item = (Item) ois.readObject();

        item.putItemToWork(id_machine);

        System.out.println("Item Worked!");
    }
    catch(ClassNotFoundException cnfe) {cnfe.printStackTrace(); }
    catch(IOException ioe) {ioe.printStackTrace(); }
}

public static void main(String[] args)
{
    MachineApp machineApp = new MachineApp(args[0]);        
}
}

2 个答案:

答案 0 :(得分:3)

对我来说,你的代码工作正常。你是从不同的线程调用wait / notify:

    public static void main(String[] args) {
    final Item item = new Item("id", "cat", "mach", false);

    Thread retrievalThread = new Thread(new Runnable() {
        @Override
        public void run() {
            item.getWorkedItem();
        }
    });

    Thread puttingThread = new Thread(new Runnable() {
        @Override
        public void run() {
            item.putItemToWork("id");
        }
    });

    retrievalThread.start();
    puttingThread.start();
}

编辑:将客户代码添加到问题后: 我可能是错的,但是您通过套接字发送项目对象,然后尝试在其上调用getWorkedItem。它不能以这种方式工作,因为一旦你通过另一方的网络对象发送项目(即使它发生在一个JVM中)将是不同的对象。因此,在其上调用notify不会触发从等待唤醒。

如何解决?好吧,您可以在服务器代码中添加某种查询界面,以便查询哪些项目有效。

如果没有家庭作业或学习练习,我认为Hadoop可以很好地满足您的需求

答案 1 :(得分:1)

对于初学者,您需要制作mchTemp volatile,因为您在一个帖子中写入此字段,并从另一个线程中读取该字段。 没有 volatile,在一个帖子中所做的更改可能在另一个网格中不可见。

private volatile String mchTemp = null;