Lorsque plusieurs threads accèdent à une classe, quelle que soit la méthode d'appel utilisée par l'environnement d'exécution ou la manière dont ces threads s'exécuteront alternativement, et rien n'est nécessaire dans le code d'appel principal. cette classe peut présenter un comportement correct malgré une synchronisation ou une coordination supplémentaire, alors cette classe est dite thread-safe.
Les objets sans état doivent être thread-safe, tels que : Servlet
. Servlet
。
由于不恰当的执行时序而出现不正确的结果的情况,就是竞争条件。
“先检查后执行”操作,即通过一个可能实效的观测结果来决定下一步的动作。比如:延迟初始化。
if(instance == null) { instance = new SomeObject(); }
“读取-修改-写入”的操作,其结果状态依赖于之前的状态。如:递增运算。
long count = 0; count++;
原子操作是指,对于访问同一个状态的所有操作(包括此操作本身)来说,这个操作是以一个原子方式执行(不可分割)的操作。
为了确保线程安全性,包含了一组必须以原子方式执行的操作,称为复合操作。
递增运算可以使用一个现有的线程安全类,确保线程安全性。如:
AtomicLong count = new AtomicLong(0); count.incrementAndGet();
如果一个类只有一个状态变量,可以通过使用线程安全的状态变量来确保类的线程安全性。当一个类有更多的状态时,仅仅添加更多的线程安全状态变量是不够的。为了确保状态的一致性,必须在单个原子操作中更新所有相关的状态变量。
Java提供一种内置锁:同步代码块,它包括:一个作为锁的对象引用、一个作为由这个锁保护的代码块。
以关键字synchronized
来修饰的方法就是一种横跨整个方法体的同步代码块,其中该同步代码块的锁就是方法调用所在的对象。静态的synchronized
public class Widget { public synchronized void doSomething() { //...... } } public class LoggingWidget extends Widget { public synchronized void doSomething() { //...... super.doSomething();//假如没有可重入的锁,该语句将产生死锁。 } }
@ThreadSafe public class SynchronizedFactorizer implements Servlet { @GuardedBy("this") private BigInteger lastNumber; @GuardedBy("this") private BigInteger[] lastFactors; public synchronized void service(ServletRequest req, ServletResponse resp) { BigInteger i = extractFromRequest(req); if (i.equals(lastNumber)) encodeIntoResponse(resp, lastFactors); else { BigInteger[] factors = factor(i);//因数分解计算 lastNumber = i; lastFactors = factors;//存放上一次计算结果 encodeIntoResponse(resp, factors); } } }
public class CachedFactorizer implements Servlet { @GuardedBy("this") private BigInteger lastNumber; @GuardedBy("this") private BigInteger[] lastFactors; public void service(ServletRequest req, ServletResponse resp) { BigInteger i = extractFromRequest(req); BigInteger[] factors = null; synchronized (this) { if (i.equals(lastNumber)) { factors = lastFactors.clone(); } } if (factors == null) { factors = factor(i); synchronized (this) { lastNumber = i; lastFactors = factors.clone(); } } encodeIntoResponse(resp, factors); } }
synchronized
est un bloc de code synchronisé qui couvre tout le corps de la méthode, et le verrou du bloc de code synchronisé est l'objet où la méthode est appelée. La méthode statique synchronisée
utilise l'objet Class comme verrou. 🎜🎜Lorsqu'un thread entre dans un bloc de code synchronisé, il acquiert automatiquement le verrou ; et lorsque le thread sort du bloc de code synchronisé, il libère automatiquement le verrou ; Au plus un thread peut détenir ce verrou, le code synchronisé est donc exécuté de manière atomique. 🎜🎜3.2 Réentrée🎜🎜Le verrou intégré est réentrant, ce qui signifie que la granularité de l'opération pour acquérir le verrou est le thread, pas l'appel. Lorsqu'un thread tente de réacquérir un verrou qu'il détient déjà, la requête réussit également. 🎜🎜La réentrée améliore encore l'encapsulation du comportement de verrouillage et simplifie le développement de code concurrent orienté objet. 🎜rrreee🎜4. Protéger l'état avec un verrou🎜🎜Pour une variable d'état variable accessible par plusieurs threads en même temps, vous devez maintenir le même verrou lors de l'accès. Dans ce cas, la variable d'état est dite. être contrôlé par ce verrou protégé. 🎜🎜5. Vivacité et performances🎜🎜L'utilisation à gros grain des verrous garantit la sécurité des threads, mais elle peut entraîner des problèmes de performances et de vivacité, tels que : 🎜rrreee🎜Vous pouvez vous assurer que le servlet est cohérent en réduisant la coiffure du bloc de code de synchronisation, tout en maintenant la sécurité des threads. Ne divisez pas ce qui devrait être des opérations atomiques en plusieurs blocs de code synchronisés. Essayez de séparer les opérations qui n'affectent pas l'état partagé et qui prennent beaucoup de temps à s'exécuter à partir du code synchronisé. Tel que : 🎜rrreeeCe 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!