Blocage se produit lorsque les threads (ou quel que soit votre plate-forme d'appels de ses unités d'exécution) acquérir des ressources, où chaque ressource ne peut être détenu que par un seul thread à la fois, et tient à ces ressources d'une manière qui la détient ne peut pas être éliminée, et il existe la "circulaire" de la relation entre les fils de telle sorte que chaque fil dans le blocage est en attente pour acquérir une ressource détenue par un autre thread.
Donc, un moyen facile d'éviter un blocage est de donner quelques total de la commande de ressources et d'imposer une règle que les ressources ne sont jamais acquises par les fils dans l'ordre. À l'inverse, un blocage peut être créé intentionnellement par les threads en cours d'exécution que l'acquisition des ressources, mais n'acquièrent pas dans l'ordre. Par exemple:
Deux fils, deux serrures. Le premier thread exécute une boucle qui tente d'acquérir les verrous dans un certain ordre, le deuxième thread exécute une boucle qui tente d'acquérir les verrous dans l'ordre inverse. Chaque thread libère les deux serrures après la réussite de l'acquisition d'une écluse.
public class HighlyLikelyDeadlock {
static class Locker implements Runnable {
private Object first, second;
Locker(Object first, Object second) {
this.first = first;
this.second = second;
}
@Override
public void run() {
while (true) {
synchronized (first) {
synchronized (second) {
System.out.println(Thread.currentThread().getName());
}
}
}
}
}
public static void main(final String... args) {
Object lock1 = new Object(), lock2 = new Object();
new Thread(new Locker(lock1, lock2), "Thread 1").start();
new Thread(new Locker(lock2, lock1), "Thread 2").start();
}
}
Maintenant, il y a eu quelques commentaires à cette question que souligner la différence entre la probabilité et la certitude de blocage. Dans un certain sens, la distinction est une question théorique. À partir d'un point de vue pratique, j'aimerais voir l'exécution d'un système qui ne fait pas l'impasse avec le code que j'ai écrit ci-dessus :)
Cependant, des questions d'entrevue peut être académique, à la fois, et ce DONC, la question n'ont que le mot "certainement" dans le titre, ce qui suit est un programme qui certainement les blocages. Deux Locker
des objets sont créés, chacun est donné deux écluses et un CountDownLatch
utilisé pour la synchronisation entre les threads. Chaque Locker
les verrous de la première écluse, puis le compte à rebours une fois le loquet. Lorsque les deux fils ont acquis un verrou et compté le loquet, ils passent devant le loquet de la barrière et de tenter d'acquérir un deuxième verrou, mais dans chaque cas, le thread est déjà titulaire de la serrure souhaité. Cette situation entraîne une certaine impasse.
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class CertainDeadlock {
static class Locker implements Runnable {
private CountDownLatch latch;
private Lock first, second;
Locker(CountDownLatch latch, Lock first, Lock second) {
this.latch = latch;
this.first = first;
this.second = second;
}
@Override
public void run() {
String threadName = Thread.currentThread().getName();
try {
first.lock();
latch.countDown();
System.out.println(threadName + ": locked first lock");
latch.await();
System.out.println(threadName + ": attempting to lock second lock");
second.lock();
System.out.println(threadName + ": never reached");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
public static void main(final String... args) {
CountDownLatch latch = new CountDownLatch(2);
Lock lock1 = new ReentrantLock(), lock2 = new ReentrantLock();
new Thread(new Locker(latch, lock1, lock2), "Thread 1").start();
new Thread(new Locker(latch, lock2, lock1), "Thread 2").start();
}
}