dise que j'ai un thread a strong> ajoute des éléments à cette liste: plus tard, thread b fort> prend la liste et, par exemple, le stocke dans un dB: Dois-je faire une synchronisation supplémentaire lors de l'écriture (fil a) et la lecture (thread b) pour assurer le thread B voit la liste de la gauche ou est-ce que cela est pris en charge par l'atomicreference? p> En d'autres termes: si j'ai une atomération à un objet mutable, et un thread change cet objet, les autres threads voient ce changement immédiatement? p> edit: p> Peut-être qu'un exemple de code est peut-être dans l'ordre suivant: p> Que se passe-t-il ici est que je crée quatre threads de travailleur pour analyser certains Texte (ceci est le lecteur Étant donné que le nombre de lignes dans le texte n'est pas un multiple de la taille du lot, les derniers objets se retrouvent dans un lot qui n'est pas rincé, car il n'est pas plein. Ces lots restants sont donc insérés par le thread principal. P> i utilise atomicreference code> à une liste d'objets:
batch.get (). Ajouter (o); code> p>
insertBatch (batch.get ()); code> p>
dans le paramètre code> dans le processus
processus () code> méthode). Chaque travailleur enregistre les lignes qu'il a analysées dans un lot et afflète le lot lorsqu'il est plein (
dao.inserbatch (Batch.EttandSet (New ArrayList
atomicreference.getandset () code> pour remplacer le lot complet avec un vide vide. Ce programme est correct en matière de filetage? P> p>
4 Réponses :
euh ... ça ne marche pas vraiment comme ça. Par conséquent, les opérations de lecture / écriture sur le contenu de la liste nécessitent une synchronisation distincte. P>
EDIT STRT>: Donc, à juger de votre code mis à jour et le commentaire que vous avez posté, définissez la référence locale à atomicreference code> garantit que la référence elle-même est visible sur des threads I.e. Si vous l'attribuez une référence différente de celle de l'original, la mise à jour sera visible. Il ne fait aucune garantie quant au contenu réel de l'objet que la référence pointe vers. P>
volatile code> suffit pour assurer la visibilité. P>
D'accord, j'ai ajouté un exemple de code à ma question ci-dessus. J'utilise atomicreference.getandset () code> pour remplacer un lot complet avec un frais frais. Est-ce que j'ai encore besoin de synchronisation supplémentaire?
Oui, votre code est correct, bien que l'utilisation de atomicreference code> ne semble pas être nécessaire ici.
@Tudor pensait exactement la même chose. En fait, le getAndset () ne peut pas faire ce qu'il veut, c'est parce qu'il obtiendra la valeur actuelle, puis modifier la valeur de l'atomérence.
@Tudor: Oui, c'est ce que je pensais aussi. Mais le problème est que le lot doit être déclaré final code> pour pouvoir l'utiliser dans la
OnNewObject () code> méthode de mon gestionnaire (anonyme). Quoi qu'il en soit, j'ai décidé de fessoire de la classe anonyme intérieure
de classe code> en faveur d'un
parseandinssertask code> de classe code> qui implémente
appelable code> et faire lot une variable d'instance de la tâche, au lieu d'une variable locale.
Notez que si vous n'avez pas besoin de faire des opérations de comparaison atomique-and-swap, vous pouvez simplement utiliser une variable code> volatile code> plutôt qu'un atomreference code>.
@Bossie: Dans ce cas, la volatilité devrait être suffisante, bien que l'appel à futurs.Oget puisse introduire une clôture de mémoire, mais je ne suis pas sûr. Il suffit de le laisser comme volatile.
ajout à Tudor S Réponse: Vous em> devront faire le Si vous pouvez vous échapper avec un threadsafe mais gardez à l'esprit: même " Simple "constructions comme ceci sont pas em> threadsafe avec ceci: p> ArrayList code> Threadsafe ou - en fonction de vos besoins - encore plus gros blocs de code.
ArrayList Code> Vous pouvez "décorer" cela comme ceci: p>
Le Ce son est comme si vous devriez utiliser un quelque chose comme: p> atomicreference code> ne vous aidera que par la référence à la liste, elle ne fera rien à la liste elle-même. Plus particulièrement, dans votre scénario, vous rencontrerez presque certainement des problèmes lorsque le système est sous charge dans lequel le consommateur a pris la liste pendant que le producteur l'ajout d'un élément.
BlockingQueue code>. Vous pouvez ensuite limiter l'empreinte mémoire si vous producteur est plus rapide que votre consommateur et laissez la file d'attente de la queue de toutes les contentions. P>
static final int PROCESSES = 4;
static final int batchSize = 10;
public void process(Reader in) throws IOException, InterruptedException {
final List<Future<Void>> tasks = new ArrayList<Future<Void>>();
ExecutorService exec = Executors.newFixedThreadPool(PROCESSES);
// Queue of objects.
final ArrayBlockingQueue<Object> queue = new ArrayBlockingQueue<Object> (batchSize * 2);
// The final object to post.
final Object FINISHED = new Object();
// Start the producers.
for (int i = 0; i < PROCESSES; i++) {
tasks.add(exec.submit(new Callable<Void>() {
@Override
public Void call() throws IOException {
Processor.this.parser.parse(in, new Parser.Handler() {
@Override
public void onNewObject(Object event) {
queue.add(event);
}
});
// Post a finished down the queue.
queue.add(FINISHED);
return null;
}
}));
}
// Start the consumer.
tasks.add(exec.submit(new Callable<Void>() {
@Override
public Void call() throws IOException {
List<Object> batch = new ArrayList<Object>(batchSize);
int finishedCount = 0;
// Until all threads finished.
while ( finishedCount < PROCESSES ) {
Object o = queue.take();
if ( o != FINISHED ) {
// Batch them up.
batch.add(o);
if ( batch.size() >= batchSize ) {
dao.insertBatch(batch);
// If insertBatch takes a copy we could merely clear it.
batch = new ArrayList<Object>(batchSize);
}
} else {
// Count the finishes.
finishedCount += 1;
}
}
// Finished! Post any incopmplete batch.
if ( batch.size() > 0 ) {
dao.insertBatch(batch);
}
return null;
}
}));
// Wait for everything to finish.
exec.shutdown();
// Wait until all is done.
boolean finished = false;
do {
try {
// Wait up to 1 second for termination.
finished = exec.awaitTermination(1, TimeUnit.SECONDS);
} catch (InterruptedException ex) {
}
} while (!finished);
}
Umm ... de son code, il ne ressemble pas à la consommation productrice. En fait, il reprogeait une équipe de fils, chacun faisant du travail, puis les rejoignant et finissant le travail dans le fil principal. Il n'y a pas de données réelles transmises entre les threads.
Je pense que, oubliant tout le code ici, la question exacte est la suivante: p>
Dois-je faire une synchronisation supplémentaire lors de l'écriture (fil a) et lecture (thread b) pour assurer le thread B voit la liste de la manière dont une gauche l'a quitté, ou est-ce que cela est pris en charge par l'atomérence? P> blockQuote>
Donc, la réponse exacte à celle-ci est la suivante:
oui strong>, atomique prennent soin de la visibilité. Et ce n'est pas mon opinion mais le Documentation JDK une : p> Les effets de mémoire pour les accès et les mises à jour des atomiques suivent généralement les règles de volatiles, comme indiqué dans la spécification de langue Java, la troisième édition (17.4 Modèle de mémoire). strong> P>
J'espère que cela vous aidera. P>