Java Multithreading - Thread-Safe Compteur
Je commence avec un exemple très simple dans le multithreading. Je suis en train de faire un thread-safe compteur. Je veux créer deux threads d'incrémenter le compteur de façon intermittente pour atteindre les 1000. Le Code ci-dessous:
public class ThreadsExample implements Runnable {
static int counter = 1; //a global counter
public ThreadsExample() {
}
static synchronized void incrementCounter() {
System.out.println(Thread.currentThread().getName() + ": " + counter);
counter++;
}
@Override
public void run() {
while(counter<1000){
incrementCounter();
}
}
public static void main(String[] args) {
ThreadsExample te = new ThreadsExample();
Thread thread1 = new Thread(te);
Thread thread2 = new Thread(te);
thread1.start();
thread2.start();
}
}
De ce que je peux dire, le tout en boucle en ce moment signifie que seul le premier thread a accès au comptoir jusqu'à ce qu'il atteigne 1000. Sortie:
Thread-0: 1
.
.
.
Thread-0: 999
Thread-1: 1000
Comment puis-je régler ce problème? Comment puis-je obtenir les threads partagent le compteur?
Pourquoi pensez-vous que la boucle while signifie que?
Il n'y a rien de "réparer". La commutation entre les threads est cher, et le planificateur sera pas en alternance laisser les threads s'exécutent pour les appels seul à
Alors que ce est une primitive exemple et il n'y a en effet pas de point de basculer entre les threads, il y a des cas où court mais les tâches critiques comme ce ne sont pas exécutées en raison d'un thread monopolisant le moniteur, causant de threads, potentiellement arrêter les progrès. Dans ce cas, il est certainement quelque chose de "réparer", par la mise en œuvre de l'équité de la politique.
qu'entendez-vous par "correctif"? Votre programme fonctionne comme prévu. Lorsque plusieurs threads s'exécutent en parallèle, la JVM n'est pas obligé de fournir le temps processeur pour tous. Ou avez-vous vous attendez à quelque chose d'autre?
Il n'y a rien de "réparer". La commutation entre les threads est cher, et le planificateur sera pas en alternance laisser les threads s'exécutent pour les appels seul à
incrementCounter
. Augmenter votre variable de boucle de 1000 à, disons, 1000000, alors vous verrez que le fils, en effet, changement dans l'entre-deux.Alors que ce est une primitive exemple et il n'y a en effet pas de point de basculer entre les threads, il y a des cas où court mais les tâches critiques comme ce ne sont pas exécutées en raison d'un thread monopolisant le moniteur, causant de threads, potentiellement arrêter les progrès. Dans ce cas, il est certainement quelque chose de "réparer", par la mise en œuvre de l'équité de la politique.
qu'entendez-vous par "correctif"? Votre programme fonctionne comme prévu. Lorsque plusieurs threads s'exécutent en parallèle, la JVM n'est pas obligé de fournir le temps processeur pour tous. Ou avez-vous vous attendez à quelque chose d'autre?
OriginalL'auteur BrotherBarnabas | 2015-04-26
Vous devez vous connecter pour publier un commentaire.
Les deux fils ont accès à votre variable.
Le phénomène que vous voyez est appelé de threads. À l'entrée de la gardé partie de votre code (désolé, j'ai manqué plus tôt), les autres threads aurez besoin de bloquer jusqu'à ce que le thread en tenant le moniteur est fait (c'est à dire lorsque le moniteur est publié). Si l'on peut s'attendre à le thread courant passer le moniteur à l'autre thread en attente dans la ligne, pour la synchronisation de blocs, java ne garantit pas l'équité ou de la politique de commande pour le thread suivant reçoit le moniteur. Il est tout à fait possible (et même probable) pour un thread qui libère et tente d'acquérir le moniteur pour obtenir de celui-ci sur un autre thread qui a été en attente pendant un certain temps.
À Partir D'Oracle:
Tandis que les deux threads sont des exemples de "gourmand" threads (depuis ils ne cessent de libérer et de réacquérir le moniteur), thread-0 est techniquement a commencé le premier, donc d'en priver thread-1.
La solution est d'utiliser en même temps une méthode de synchronisation qui prend en charge l'équité (par exemple, ReentrantLock) comme indiqué ci-dessous:
remarque la suppression de l'
synchronized
mot-clé en faveur de la ReentrantLock dans la méthode. Un tel système, avec un surveillant de l'équité de la politique, permet de longues threads en attente d'une chance de s'exécuter, la suppression de la faim.OriginalL'auteur initramfs
Vous pouvez utiliser le
AtomicInteger
. C'est une classe qui peut être incrémenté automatiquement, de sorte que deux threads séparés en appelant sa méthode increment ne pas interleave.OriginalL'auteur Bert Peters
Bien, avec ton code, je ne sais pas comment l'avoir "exactement" par intermittence, mais si vous utilisez
Thread.yield()
après appelincrementCounter()
vous aurez une meilleure distribution.Sinon, pour ce que vous proposez, vous pouvez créer deux classe thread (ThreadsExample1 et ThreadsExample2 si vous voulez), et une autre classe pour une variable partagée.
Maintenant, la principale peut être:
Et vous devez changer votre ligne de
static int counter = 1; //a global counter
pour
private SharedVariable counter;
Et la nouvelle exécution est:
}
Oui, c'est un autre code, mais je pense que ça peut vous aider un peu.
OriginalL'auteur Shondeslitch
essayer de dormir un thread pour s'assurer que l'autre aura un go:
sleep()
est OK pour les démonstrations et des expériences, mais si jamais vous appel à sleep() dans un programme réel, alors vous avez probablement ré-inventerScheduledThreadPoolExecutor
, ou bien de faire une erreur.OriginalL'auteur almeynman