>Java >java지도 시간 >Java 동시 프로그래밍에서 스레드 안전성을 구현하는 방법

Java 동시 프로그래밍에서 스레드 안전성을 구현하는 방법

WBOY
WBOY앞으로
2023-05-21 15:14:131533검색

    1. 스레드 안전성이란 무엇입니까?

    여러 스레드가 클래스에 액세스하는 경우 런타임 환경에서 사용하는 호출 방법이나 이러한 스레드가 교대로 실행되는 방식에 관계없이 기본 호출 코드에는 아무것도 필요하지 않습니다. 이 클래스는 추가 동기화 또는 조정에도 불구하고 올바른 동작을 나타낼 수 있으며, 이 클래스를 스레드로부터 안전하다고 합니다.

    상태 비저장 객체는 서블릿과 같이 스레드로부터 안전해야 합니다. Servlet

    2.原子性

    2.1 竞争条件

    由于不恰当的执行时序而出现不正确的结果的情况,就是竞争条件。

    “先检查后执行”操作,即通过一个可能实效的观测结果来决定下一步的动作。比如:延迟初始化。

    if(instance == null) {
        instance = new SomeObject();
    }

    “读取-修改-写入”的操作,其结果状态依赖于之前的状态。如:递增运算。

    long count = 0;
    count++;

    2.2 复合操作

    原子操作是指,对于访问同一个状态的所有操作(包括此操作本身)来说,这个操作是以一个原子方式执行(不可分割)的操作。

    为了确保线程安全性,包含了一组必须以原子方式执行的操作,称为复合操作。

    递增运算可以使用一个现有的线程安全类,确保线程安全性。如:

    AtomicLong count = new AtomicLong(0);
    count.incrementAndGet();

    3.加锁机制

    如果一个类只有一个状态变量,可以通过使用线程安全的状态变量来确保类的线程安全性。当一个类有更多的状态时,仅仅添加更多的线程安全状态变量是不够的。为了确保状态的一致性,必须在单个原子操作中更新所有相关的状态变量。

    3.1 内置锁

    Java提供一种内置锁:同步代码块,它包括:一个作为锁的对象引用、一个作为由这个锁保护的代码块。

    以关键字synchronized来修饰的方法就是一种横跨整个方法体的同步代码块,其中该同步代码块的锁就是方法调用所在的对象。静态的synchronized

    2. 원자성

    2.1 경쟁 조건

    부적절한 실행 타이밍으로 인해 잘못된 결과가 발생하는 경우 경쟁 조건이 발생합니다.

    "먼저 확인하고 실행"하는 작업은 가능하고 효과적인 관찰 결과를 바탕으로 다음 작업을 결정하는 것입니다. 예: 지연 초기화.

    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);
            }
        }
    }

    2.2 복합 연산

    원자 연산은 동일한 상태에 액세스하는 모든 연산(연산 자체 포함)에 대해 이 연산이 원자 방식(분할할 수 없음)으로 수행된다는 것을 의미합니다.

    스레드 안전성을 보장하기 위해 원자적으로 수행되어야 하는 일련의 작업, 즉 복합 작업이 포함됩니다.

    증분 작업에서는 기존 스레드 안전 클래스를 사용하여 스레드 안전성을 보장할 수 있습니다. 예:

    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 중국어 웹사이트의 기타 관련 기사를 참조하세요!

    성명:
    이 기사는 yisu.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제