Maison >Java >javaDidacticiel >Les principes et scénarios d'utilisation de Synchronized en Java et l'analyse de l'utilisation et des différences de l'interface Callable
1. Cela commence par un verrouillage optimiste si les conflits de verrouillage sont fréquents, il sera converti en verrouillage pessimiste
2. Cela commence par une mise en œuvre légère du verrouillage. longtemps, longtemps, il est converti en un verrou lourd.
3. La stratégie de verrouillage rotatif qui est la plus probablement utilisée lors de la mise en œuvre de verrous légers
4 C'est un verrou injuste
5.
6. Pas un verrou en lecture-écriture2. Processus de verrouillageJVM divise les verrous synchronisés en états de verrouillage sans verrouillage, biaisés, légers et lourds. Il sera mis à niveau séquentiellement en fonction de la situation. Bias Lock Supposons que le protagoniste masculin est un verrou et que le protagoniste féminin est un fil s'il n'y a qu'un seul fil pour utiliser ce verrou, alors même si le protagoniste masculin et le protagoniste féminin n'obtiennent pas de fil. certificat de mariage (en évitant les opérations coûteuses), vous pouvez vivre heureux pour toujours. Mais la protagoniste féminine apparaît et essaie de rivaliser pour le protagoniste masculin. À ce moment-là, peu importe le coût de l'opération d'obtention d'un certificat de mariage, la protagoniste féminine. doit terminer cette action, faisant abandonner la protagoniste féminineLe biais n'est pas de verrouiller. En réalité, le "verrouillage" consiste simplement à faire une "marque de biais de verrouillage" dans l'en-tête de l'objet pour enregistrer à quel thread appartient le verrou s'il y en a. aucun autre thread ne rivalisera pour le verrou à l'avenir, alors il n'est pas nécessaire d'effectuer d'autres opérations de synchronisation (ce qui évite d'avoir à ajouter des verrous). S'il y a d'autres threads en compétition pour le verrou plus tard (ce qui). le thread auquel appartient le verrou actuel a été enregistré dans l'objet de verrouillage, il est facile d'identifier si le thread demandant actuellement le verrou est le thread précédemment enregistré), puis annulez l'original. L'état de verrouillage biaisé entre dans l'état de verrouillage léger général Le verrouillage biaisé est essentiellement équivalent au "verrouillage différé". Si vous ne pouvez pas le verrouiller, ne le verrouillez pas et essayez d'éviter une surcharge de verrouillage inutile. Mais ce qu'il faut faire Le marquage doit encore être fait, sinon ce sera le cas. impossible de distinguer quand un vrai verrouillage est requisLe verrouillage biaisé n'est pas vraiment un verrouillage, mais enregistre simplement une marque dans l'en-tête de l'objet du verrou (enregistrant le thread auquel le verrou appartient). Si aucun autre thread ne participe aux verrous concurrents, alors le. L'opération de verrouillage ne sera pas réellement effectuée, réduisant ainsi la surcharge du programme. Une fois que d'autres threads seront réellement impliqués dans la compétition, l'état de verrouillage biaisé sera annulé et l'état de verrouillage léger sera entré Verrouillage légerAvec les autres threads, entrez en compétition. , l'état de verrouillage biaisé est éliminé et l'état de verrouillage léger (verrouillage de rotation adaptatif) est entré. Le verrouillage léger ici est implémenté via CAS Vérifiez et mettez à jour un morceau de mémoire via CAS (comme null => Référencé par. ce fil)Si la mise à jour réussit, le verrou est considéré comme réussiSi la mise à jour échoue, le verrou est considéré comme occupé et l'attente de type rotation continue (sans abandonner le processeur).L'opération de rotation est Keeping La mise au ralenti du processeur est un gaspillage de ressources CPU. Par conséquent, la rotation ici ne continuera pas éternellement, mais cessera de tourner après avoir atteint un certain temps/nombre de tentatives. C'est ce qu'on appelle "adaptatif" Verrouillage lourdSi. la compétition devient plus intense et le spin ne peut pas obtenir le statut de verrouillage rapidement, il se transformera en un verrou lourd. Le verrou lourd fait ici référence à l'utilisation du mutex fourni par le noyau.Pour effectuer l'opération de verrouillage, entrez d'abord le noyau. state.Déterminez si le verrou actuel est occupé dans l'état du noyauSi le verrou n'est pas occupé, le verrouillage est réussi et le commutateur revient à l'état utilisateur.Si le verrou est occupé, le verrouillage échoue. À ce moment-là, le fil entre dans la file d'attente du verrou et se bloque. En attendant d'être réveillé par le système d'exploitation. Après une série de changements, le verrou a été libéré par d'autres fils. Le système d'exploitation a également mémorisé le fil suspendu. il a réveillé le thread et a essayé de le redémarrer. Acquérir le verrou3 Autres opérations d'optimisationÉlimination du verrouillageLe compilateur + JVM détermine si le verrou peut être éliminé. Si c'est possible, éliminez-le simplement directementCertains. les codes d'application sont synchronisés, mais en fait, ils ne sont pas utilisés dans de nombreuses applications (comme StringBuffer)StringBuffer sb = new StringBuffer(); sb.append("a"); sb.append("b"); sb.append("c"); sb.append("d");À l'heure actuelle, chaque appel d'ajout impliquera le verrouillage et le déverrouillage. un seul thread, alors ces opérations de verrouillage et de déverrouillage sont inutiles et gaspillées. Une certaine surcharge de ressources. Leader, attribuez des tâches de travail aux subordonnésMéthode 1 :Appelez, donnez la tâche 1, raccrochez.
Appelez, donnez la tâche 2, raccrochez.
Appelez, donnez la tâche 3, raccrochez
Méthode 2 :
Appelez, donnez la tâche 1, la tâche 2, la tâche 3, raccrochez le téléphone
4. Interface appelable
Qu'est-ce que Callable ?
Callable est une interface qui équivaut à encapsuler une "valeur de retour" dans un. thread. Il est pratique pour les programmeurs de calculer les résultats en utilisant le multi-threading.
Callable 和 Runnable 相对, 都是描述一个 "任务". Callable 描述的是带有返回值的任务, Runnable 描述的是不带返回值的任务.Callable 通常需要搭配 FutureTask 来使用. FutureTask 用来保存 Callable 的返回结果. 因为 Callable 往往是在另一个线程中执行的, 啥时候执行完并不确定. FutureTask 就可以负责这个等待结果出来的工作.
代码示例: 创建线程计算 1 + 2 + 3 + ... + 1000, 不使用 Callable 版本
public class Text { static class Result{ public int sum = 0; public Object locker = new Object(); } public static void main(String[] args) throws InterruptedException { Result result = new Result(); Thread t = new Thread(){ @Override public void run() { int sum = 0; for (int i = 0; i <=10000; i++){ sum += i; } result.sum = sum; synchronized (result.locker){ result.locker.notify(); } } }; t.start(); synchronized (result.locker){ while (result.sum == 0){ result.locker.wait(); } } System.out.println(result.sum); } }
代码示例: 创建线程计算 1 + 2 + 3 + ... + 1000, 使用 Callable 版本
import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; public class Text1 { public static void main(String[] args) throws ExecutionException, InterruptedException { Callable<Integer> callable = new Callable<Integer>() { @Override public Integer call() throws Exception { int sum = 0; for (int i = 0; i <=1000; i++){ sum += i; } return sum; } }; //由于Thread不能直接传一个callable实例,就需要一个辅助类来包装 FutureTask<Integer> futureTask = new FutureTask<>(callable); Thread t = new Thread(futureTask); t.start(); //尝试在主线程获取结果 //如果FutureTask中的结果还没生成。此时就会阻塞等待 //一直等到最终的线程把这个结果算出来,get返回 Integer result = futureTask.get(); System.out.println(result); } }
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!