스레드를 사용한 시나리오 - 스레드 동시성 안전성의 원인 및 솔루션

우리는 컴퓨터를 구입할 때 컴퓨터 CPU의 코어와 스레드 수에 특별한 주의를 기울이는 경우가 많습니다. 이것은 종종 컴퓨터의 속도를 결정하기 때문에

, 이 모든 것은 작업 관리자에서 찾을 수 있습니다.

 

이때 멀티스레드 연산에 노출되더라도 스레드가 무엇인지 의심할 수 있다.

Baidu 백과사전에 따르면 스레드 (영어: thread)는 운영 체제가 작업 스케줄링을 수행할 수 있는 가장 작은 단위입니다 . 이는 프로세스 에 포함되며 프로세스 의 실제 작동 단위 입니다 . 스레드는 프로세스 의 단일 순차적 제어 흐름을 의미합니다.여러 스레드가 프로세스에서 동시에 실행될 수 있으며 각 스레드는 서로 다른 작업을 병렬로 수행합니다. Unix System V 및 SunOS 에서는 경량 프로세스(lightweight process)라고도 하지만 경량 프로세스는 커널 스레드(kernel thread), 사용자 스레드(user thread)는 스레드라고 합니다.

그렇다면 멀티스레딩은 언제 사용해야 할까요?

1 : 동시에 여러 작업을 처리
예를 들어 화상 회의 시스템:
1 : 오디오 전송
2 : 영상전송
3 : 데스크톱 공유
2 : 여러 개의 동일한 작업을 동시에 처리합니다( 동시성 이라고도 함 ).
작은 공 5000
1 : 하나의 스레드가 공 그리기 및 이동과 같은 모든 작업을 폴링합니다.
공의 수가 증가할 때: 폴링 시간이 오래 걸림
이러한 공을 처리하기 위한 다중 스레드:
단일 스레드는 일부만 담당합니다.
3: 파이프라인 모드
완전한 퀘스트 체인
작업 1 :
작업 2 : 작업 1 을 완료해야 합니다.
작업 3 : 작업 2 를 완료해야 합니다.

이렇게 하면 각 스레드를 가장 효율적으로 사용할 수 있습니다.

스레드 동시성 안전성이란 무엇입니까?

동시 작업을 처리할 때 여러 쓰레드가 같은 리소스에서 동작하기 때문에 연산 시간이 시차를 두지 않아 메모리에서 연산이 반복되어 데이터 혼란과 보안 문제가 발생한다.

 예를 들면 다음과 같습니다. 각 스레드에 대한 작업, 즉 num에 1000배를 추가했습니다.

스레드 스택 작업 단계: 힙 메모리에서 num 가져오기 -->> num 복사본을 스레드 스택에 복사 -->> num++ 작업 수행

——>>num을 반환하고 힙 메모리의 num에 할당합니다.

이것이 올바른 것처럼 보이지만 반드시 하나의 스레드만 동시에 힙 메모리에서 num을 가져오는 것은 아닙니다.

여러 스레드가 가져오면 num++ 연산이 반복되어 최종 숫자가 3000++ 미만이 되고 데이터가 잘못됩니다.

 일반적인 상황:

1 : 읽기 및 읽기는 스레드 안전 문제를 일으키지 않습니다.
2: 읽기와 쓰기가 생성됩니다.
3 : 쓰기 쓰기가 생성됩니다.

이 문제를 어떻게 해결할 수 있습니까?

결국, 이 데이터가 은행의 금액을 나타낸다면 그것이 잘못되는 것을 원하지 않을 것입니다! ! !

잠금 사용( 동기화됨) :

코드 블록을 동기화하고, 리소스를 잠그고, 현재 모니터 잠금을 보유하고 있는 스레드만 리소스에 액세스하도록 허용합니다.

다음과 같이 이해할 수 있습니다. 스레드가 힙 메모리에서 num을 복사하면 힙 메모리가 일시적으로 "잠겨" 액세스할 수 없습니다.

스레드가 num 작업을 완료하고 num을 힙 메모리에 할당한 경우에만 다른 스레드가 힙 메모리에 액세스하기 위해 계속 경쟁하도록 "잠금 해제" 됩니다 .

이렇게 하면 작업이 반복되지 않고 데이터가 잘못되지 않으며 동시에 경쟁 액세스 메커니즘으로 인해 작업 속도가 크게 가속화됩니다.

예는 다음과 같습니다.

작업 클래스:

public class Task{

     static int num=0;//静态变量,处于堆内存中

    public static void main(String[] args) {

        Task tt = new Task();
        Thread t1=new Thread(new Threadsy(tt));
        t1.start();
        Thread t2=new Thread(new Threadsy(tt));
        t2.start();
        Thread t3=new Thread(new Threadsy(tt));
        t3.start();//创建并启动三个线程

        try {
            t1.join();
            t2.join();
            t3.join();
        } catch (InterruptedException e) {
            throw new RuntimeException (e);
        }//阻塞,直到线程全部完成,便于得到最终结果

        System.out.println(tt.num);//检验结果
        
    }
}

스레드 클래스:

public class Threadsy implements Runnable {

    Task tt = new Task();
    public Threadsy(Task tt) {
        this.tt = tt;
    }//构析方法,便于取堆内存中的num。

    static Object object = new Object();//值得注意的是,Object要保证是静态变量,存在堆内存中,才可以通过它“锁住”堆内存的num

    public void run() {
            for (int i = 0; i < 1000; i++) {

                synchronized (object/*只能“锁”对象*/) {
                    tt.num++;
                }//给堆内存上锁,保证线程安全

        }
    }//线程操作方式
}

결과는 다음과 같습니다.

모든 것이 정상입니다! ! !

 

리소스 잠금을 제거하면 다음과 같습니다.

즉, 데이터 오류:

동시 작업의 경우 멀티스레딩을 사용하면 효율성을 크게 높일 수 있지만 스레드 안전 문제에 큰 주의를 기울여야 합니다!

 

추천

출처blog.csdn.net/AkinanCZ/article/details/126058188