Dans tout le processus depuis le début d'un thread jusqu'à la fin de l'accès, si un objet d'accès est modifié par un autre thread, alors un problème de sécurité du thread se produira pour le thread actuel ; if Pendant tout le processus d'accès, aucun objet n'est modifié par d'autres threads, ce qui signifie qu'il est thread-safe.
La première est un environnement multithread, c'est-à-dire , il y a plusieurs threads en même temps. Opérateur, l'environnement à thread unique n'a pas de problèmes de sécurité des threads. Dans un environnement monothread, toute opération, y compris les opérations de modification, est émise par l'opérateur lui-même. L'opérateur a non seulement un objectif clair lorsqu'il émet l'opération, mais est également conscient de l'impact de l'opération.
Plusieurs opérateurs (threads) doivent faire fonctionner le même objet Ce n'est que lorsque plusieurs opérateurs font fonctionner un objet en même temps que l'impact du comportement peut être immédiatement transféré à. d'autres opérations qui.
Les opérations de plusieurs opérateurs (threads) sur le même objet doivent inclure des opérations de modification. Il n'y a pas de problème de sécurité des threads en lecture conjointe, car l'objet ne l'est pas. modifié. Inchangé, ne peut avoir d’impact.
De ce qui précède, on peut voir que la cause première des problèmes de sécurité des threads est que les données partagées peuvent être modifiées simultanément, c'est-à-dire lorsqu'un thread lit , un autre fil de discussion est autorisé à réviser.
Selon les conditions dans lesquelles les problèmes de sécurité des threads surviennent, l'idée pour résoudre les problèmes de sécurité des threads est d'éliminer l'apparition de problèmes de sécurité des threads Environnement problématique :
Éliminer les données partagées : les variables membres et les variables statiques sont partagées par plusieurs threads, convertissez ces variables globales en variables locales et stockez les variables locales sur la pile. S'il n'y a pas de partage entre les threads, il n'y aura pas d'environnement propice aux problèmes de sécurité des threads. Éliminez les défauts des données partagées : si vous avez besoin d'un objet pour collecter des informations de chaque thread ou transférer des informations entre les threads, cet objectif ne peut pas être atteint si vous éliminez l'objet partagé.
Utilisez le mécanisme de synchronisation des threads : verrouillez les opérations de lecture et d'écriture en même temps afin qu'un seul thread puisse accéder aux données partagées en même temps. Si l'opération d'écriture est uniquement verrouillée et qu'un seul thread peut effectuer l'opération d'écriture en même temps et que l'opération de lecture n'est pas restreinte, permettant à plusieurs threads de lire simultanément, des lectures non répétables peuvent se produire, comme une lecture qui dure longtemps. Les threads lisent les données à la même position d'index du tableau sur une longue période de temps. Au cours des deux lectures, un thread a modifié les données à l'index, provoquant la lecture des données par le thread à partir du même index. être incohérent. Le fait de verrouiller à la fois la lecture et l'écriture, ou uniquement l'écriture, dépend des besoins spécifiques. L'inconvénient du mécanisme de synchronisation est qu'il réduit le débit du programme.
Créer une copie : utilisez ThreadLocal pour créer une copie de la variable pour chaque thread. Chaque thread fonctionne indépendamment sans s'affecter. Cette méthode est essentiellement une mise en œuvre visant à éliminer l’idée de données partagées.
4. Visibilité
Chaque thread conserve une copie de la variable partagée en interne. 🎜>
public class NoVisibility { private static boolean ready; private static int number; public static class ReadThread extends Thread { public void run() { while(!ready ) Thread. yield(); System. out.println(number); } } public static void main(String [] args) { new ReadThread().start(); number = 42; ready = true ; } }Le code ci-dessus peut générer 0 ou rien. Pourquoi rien ne peut-il être sorti ? Parce que nous définissons ready sur true dans le thread principal, mais que la valeur ready que nous définissons peut ne pas être lue dans ReadThread, donc Thread.yield() continuera à être exécuté dans ReadThread. Pourquoi cela pourrait-il être 0 ? Si ReadThread peut lire notre valeur, il peut d'abord lire que la valeur prête est vraie, et avant de lire et de mettre à jour la valeur numérique, ReadThread affichera la valeur numérique conservée, qui est 0. Notez que tout ce qui précède sont des hypothèses. Nous ne pouvons pas prédire comment ReadThread et le thread principal interagiront en l'absence de synchronisation. Les deux situations ci-dessus ne sont que deux possibilités. Alors comment éviter ce problème ? Tout simplement, chaque fois que des données doivent être partagées entre plusieurs threads, utilisez une synchronisation appropriée. 4.1, Verrouillage et visibilité
内置锁可以用于确保某个线程以一种可预测的方式查看另一个线程的执行结果,当线程A进入某同步代码块时,线程B随后进入由同一个锁保护的同步代码块,此时,线程B执行由锁保护的同步代码块时,可以看到线程A之前在同一同步代码块中的所有操作结果,如果没有同步,那么就无法实现上述保证。
加锁的含义不仅仅局限于互斥行为,还包括内存可见性。为了确保所有线程都能看到共享变量的最新值,所有执行读操作或者写操作的线程都必须在同一个锁上同步。
4.2、volatile变量
volatile是一种比synchronized关键字轻量级的同步机制,volatile关键字可以确保变量的更新操作通知到其他线程。
下面是volatile的典型用法:
volatile boolean asleep; ... while(!asleep) doSomeThing();
加锁机制既可以确保可见性,又可以确保原子性,而volatile变量只能确保可见性。
5、总结
编写线程安全的代码,其核心在于要对状态访问操作进行管理。编写线程安全的代码时,有两个关注点,一个是原子性问题,一个是可见性问题,要尽量避免竞态条件错误。
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!