여러 스레드가 클래스에 액세스하는 경우 런타임 환경에서 사용하는 호출 방법이나 이러한 스레드가 교대로 실행되는 방식에 관계없이 기본 호출 코드에는 아무것도 필요하지 않습니다. 이 클래스는 추가 동기화 또는 조정에도 불구하고 올바른 동작을 나타낼 수 있으며, 이 클래스를 스레드로부터 안전하다고 합니다.
상태 비저장 객체는 서블릿
과 같이 스레드로부터 안전해야 합니다. 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); } }3. 잠금 메커니즘🎜🎜클래스에 상태 변수가 하나만 있는 경우 스레드로부터 안전한 상태 변수를 사용하여 클래스의 스레드 안전성을 보장할 수 있습니다. 클래스에 더 많은 상태가 있으면 스레드로부터 안전한 상태 변수를 더 추가하는 것만으로는 충분하지 않습니다. 상태 일관성을 보장하려면 모든 관련 상태 변수를 단일 원자성 작업으로 업데이트해야 합니다. 🎜🎜3.1 내장 잠금🎜🎜Java는 내장 잠금을 제공합니다: 동기화된 코드 블록, 포함: 잠금으로 사용되는 객체 참조 및 코드로 참조 이 잠금 장치로 보호됩니다. 🎜🎜
synchronized
키워드로 수정된 메소드는 메소드 본문 전체에 걸쳐 있는 동기화된 코드 블록이며, 동기화된 코드 블록의 잠금은 메소드가 호출되는 객체입니다. 정적 synchronized
메소드는 Class 객체를 잠금으로 사용합니다. 🎜🎜스레드가 동기화된 코드 블록에 들어가면 자동으로 잠금을 획득하고 스레드가 동기화된 코드 블록을 종료하면 자동으로 잠금을 해제합니다. 최대 하나의 스레드가 이 잠금을 보유할 수 있으므로 동기화된 코드는 원자적으로 실행됩니다. 🎜🎜3.2 재진입🎜🎜 내장 잠금은 재진입이 가능합니다. 즉, 잠금을 획득하기 위한 작업의 세분성은 호출이 아니라 스레드라는 의미입니다. 스레드가 이미 보유하고 있는 잠금을 다시 획득하려고 시도하면 요청도 성공합니다. 🎜🎜재진입은 잠금 동작의 캡슐화를 더욱 개선하고 객체 지향 동시 코드 개발을 단순화합니다. 🎜rrreee🎜4. 잠금으로 상태를 보호하세요🎜🎜여러 스레드에서 동시에 액세스할 수 있는 변수 상태 변수의 경우 액세스할 때 동일한 잠금을 유지해야 합니다. 이 잠금 장치로 보호됩니다. 🎜🎜5. 활성 및 성능🎜🎜 잠금을 대략적으로 사용하면 스레드 안전성이 보장되지만 다음과 같은 성능 및 활성 문제가 발생할 수 있습니다. 🎜rrreee🎜동기화 코드 블록 헤어스타일을 축소하여 서블릿의 일관성을 보장할 수 있습니다. 스레드 안전성을 유지하면서. 원자성 작업이어야 하는 작업을 여러 개의 동기화된 코드 블록으로 분할하지 마세요. 공유 상태에 영향을 주지 않고 실행하는 데 시간이 오래 걸리는 작업을 동기화된 코드에서 분리하세요. 예: 🎜rrreee위 내용은 Java 동시 프로그래밍에서 스레드 안전성을 구현하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!