Producteur/Consommateur threads à l'aide d'une File d'attente
J'aimerais créer une sorte de Producer/Consumer
filetage app. Mais je ne suis pas sûr de ce que la meilleure façon de mettre en œuvre une file d'attente entre les deux.
J'ai donc quelques avec deux idées (qui peuvent être tout à fait tort). Je voudrais savoir qui serait le mieux et si les deux sucent alors quelle serait la meilleure façon de mettre en œuvre la file d'attente. C'est principalement ma mise en œuvre de la file d'attente dans ces exemples, que je suis préoccupé. Je suis de l'extension d'une classe de File d'attente qui est une maison de classe et est thread-safe. Ci-dessous deux exemples avec 4 classes de chacun.
Classe principale-
public class SomeApp
{
private Consumer consumer;
private Producer producer;
public static void main (String args[])
{
consumer = new Consumer();
producer = new Producer();
}
}
Classe de consommateur-
public class Consumer implements Runnable
{
public Consumer()
{
Thread consumer = new Thread(this);
consumer.start();
}
public void run()
{
while(true)
{
//get an object off the queue
Object object = QueueHandler.dequeue();
//do some stuff with the object
}
}
}
Producteur de la classe
public class Producer implements Runnable
{
public Producer()
{
Thread producer = new Thread(this);
producer.start();
}
public void run()
{
while(true)
{
//add to the queue some sort of unique object
QueueHandler.enqueue(new Object());
}
}
}
Classe de file d'attente-
public class QueueHandler
{
//This Queue class is a thread safe (written in house) class
public static Queue<Object> readQ = new Queue<Object>(100);
public static void enqueue(Object object)
{
//do some stuff
readQ.add(object);
}
public static Object dequeue()
{
//do some stuff
return readQ.get();
}
}
OU
Classe principale-
public class SomeApp
{
Queue<Object> readQ;
private Consumer consumer;
private Producer producer;
public static void main (String args[])
{
readQ = new Queue<Object>(100);
consumer = new Consumer(readQ);
producer = new Producer(readQ);
}
}
Classe de consommateur-
public class Consumer implements Runnable
{
Queue<Object> queue;
public Consumer(Queue<Object> readQ)
{
queue = readQ;
Thread consumer = new Thread(this);
consumer.start();
}
public void run()
{
while(true)
{
//get an object off the queue
Object object = queue.dequeue();
//do some stuff with the object
}
}
}
Producteur de la classe
public class Producer implements Runnable
{
Queue<Object> queue;
public Producer(Queue<Object> readQ)
{
queue = readQ;
Thread producer = new Thread(this);
producer.start();
}
public void run()
{
while(true)
{
//add to the queue some sort of unique object
queue.enqueue(new Object());
}
}
}
Classe de file d'attente-
//the extended Queue class is a thread safe (written in house) class
public class QueueHandler extends Queue<Object>
{
public QueueHandler(int size)
{
super(size); //All I'm thinking about now is McDonalds.
}
public void enqueue(Object object)
{
//do some stuff
readQ.add();
}
public Object dequeue()
{
//do some stuff
return readQ.get();
}
}
Et go!
- Les producteurs de mettre en file d'attente et de la Consommation file d'attente, btw. Pas vice-versa..
- Oh, et ne pas commencer le Fils d'un constructeur!! Ce thread a pu observer l'objet dans un état incohérent. Reportez-vous à "Java Simultanéité dans la Pratique" pour plus de détails..
- Grâce Zwei, la mise en file d'attente était chose de moi d'être floue. départ le Fil de constructeur chose devrais-je plutôt exécuter une intiliazation méthode et de le démarrer, il ou devrait-il commencer à partir de la méthode main de la classe?
Vous devez vous connecter pour publier un commentaire.
Java 5+ dispose de tous les outils dont vous avez besoin pour ce genre de chose. Vous souhaitez:
ExecutorService
;ExecutorService
;BlockingQueue
.Je dis "si nécessaire", pour (3), en raison de mon expérience, c'est une étape inutile. Tout ce que vous faire est de soumettre de nouvelles tâches pour le consommateur exécuteur de service. Donc:
De sorte que le
producers
soumettre directement àconsumers
.newFixedThreadPool
fera pas thread-safe.OK, comme d'autres, la meilleure chose à faire est d'utiliser
java.util.concurrent
paquet. Je recommande fortement "Java Simultanéité dans la Pratique". C'est un grand livre qui couvre presque tout ce que vous devez savoir.Comme pour votre mise en œuvre, comme je l'ai noté dans les commentaires, ne pas faire des filets de Constructeurs, il peut être dangereux.
Laissant cela de côté, la deuxième mise en œuvre semblent mieux. Vous ne voulez pas mettre les files d'attente dans les champs statiques. Vous êtes probablement juste de perdre de la souplesse pour rien.
Si vous voulez aller de l'avant avec votre propre mise en œuvre (pour but d'apprentissage, je suppose?), fournir un
start()
méthode au moins. Vous devez construire l'objet (vous pouvez instancier laThread
objet), puis d'appelerstart()
pour démarrer le thread.Edit:
ExecutorService
ont leur propre file d'attente donc cela peut être source de confusion.. Voici quelque chose pour vous aider à démarrer.MODIFIER:
Pour le producteur, au lieu de
while(true)
, vous pouvez faire quelque chose comme:De cette façon, vous pouvez arrêter l'exécuteur en appelant
.shutdownNow()
. Si vous souhaitez utiliserwhile(true)
, il ne s'arrête pas.Également de noter que la
Producer
est toujours vulnérable àRuntimeExceptions
(c'est à dire unRuntimeException
va arrêter le traitement)Vous êtes en train de réinventer la roue.
Si vous avez besoin de persévérance et d'autres fonctionnalités d'entreprise utilisation JMS (je vous suggère de ActiveMq).
Si vous avez besoin d'vite en mémoire les files d'utiliser l'un des impementations de java La file d'attente.
Si vous avez besoin de support java 1.4 ou version antérieure, utilisez Doug Lea excellent simultanées paquet.
J'ai étendu cletus proposé de répondre à de travail exemple de code.
ExecutorService
(pse) accepteProducer
tâches.ExecutorService
(ces) accepteConsumer
tâches.Producer
etConsumer
actionsBlockingQueue
.Producer
tâches génère des numéros différents.Consumer
tâches peuvent consommer numéro généré parProducer
Code:
de sortie:
Note. Si vous n'avez pas besoin de plusieurs Producteurs et les Consommateurs, les garder seul le Producteur et le Consommateur. J'ai ajouté plusieurs Producteurs et les Consommateurs pour mettre en valeur les capacités de BlockingQueue entre plusieurs Producteurs et les Consommateurs.
C'est un code très simple.
BlockingQueue.java
Consumer.java
ProducerConsumer_Main.java