>  기사  >  Java  >  학습 문서: Java의 동기화 정보

학습 문서: Java의 동기화 정보

php是最好的语言
php是最好的语言원래의
2018-08-09 16:48:442043검색

일상적인 개발 작업에서 우리는 멀티 스레드 프로그래밍이나 일부 동시성 문제에 다소 노출됩니다. 운영 체제 및 시스템 하드웨어가 업그레이드됨에 따라 개발에 동시 프로그래밍이 점점 더 많이 사용되고 있습니다. 멀티스레딩은 시스템 리소스를 더 많이 활용하기 위한 것이지만, 멀티스레딩을 사용할 경우에도 몇 가지 문제가 있을 수 있습니다. 먼저 코드를 살펴보겠습니다.

    private static int i = 0;

    private static void increse(){
        i++;
    }

    public static void main(String[] args) {
    Thread[] threads = new Thread[20];
        for (int i = 0; i < threads.length; i++){
            threads[i] = new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int j = 0; j < 10000; j++){
                        increse();
                    }
                }
            });
            threads[i].start();
        }
        
        while (Thread.activeCount() > 1){
            Thread.yield();
        }
        
        System.out.println(i);
    }

우선 이 코드를 보면 문제가 없지만, 멀티 쓰레드 환경이라면 이 코드를 실행한 결과는 기본적으로 20개의 쓰레드가 시작되고, 각 쓰레드마다 다릅니다. increse() 메소드는 변수 i에 대해 할당 작업을 수행합니다. 예상 출력은 200000이어야 하는데 출력이 매번 다른 이유는 무엇입니까? 시간? 모직물? 그 이유는 바로 i++에 있습니다. 이것이 동시성 문제의 근본 원인입니다. 그런데 겉으로는 단순해 보이는 i++에 왜 이런 문제가 있는 것일까요? 여기서는 java 메모리 모델(JMM)에서 먼저 학습합니다. 먼저, JMM은 실행 시 각 스레드가 작업 메모리를 갖게 된다고 규정한 다음 변수 i를 지정합니다. 는 메인 메모리에 저장됩니다. 스레드는 데이터를 계산할 때마다 현재 변수의 값을 얻기 위해 메인 메모리로 이동해야 합니다. 간단히 말하면 스레드는 변수 i를 변경합니다. code> 계산 결과를 얻은 후 데이터가 주 메모리에 새로 고쳐지지 않았습니다. 이때 다른 스레드는 원래 값을 얻었습니다. 즉, 이 스레드에서 얻은 데이터가 최신인지 알 수 없습니다. . 그러나 이는 <code>JMM의 관점에서 간략하게 설명한 것일 뿐입니다. i++의 단순해 보이는 이 작업에는 실제로 i 값을 얻는 세 가지 작업이 포함됩니다. 값을 설정하려면 i를 증가시킨 다음 i에 값을 할당하세요. 이러한 작업 중에 다른 스레드는 많은 작업을 수행하는 데 많은 시간을 갖게 됩니다. 그러면 일부 사람들은 이 i++ 작업을 동기화하는 데 충분합니까? 네, 어떻게 동기화하나요? increse()方法对变量i进行一个赋值操作,预期的一个输出应该是200000,但是为什么会每一次的输出都不太一样呢?原因就在于这个地方i++,这里就是产生并发问题的根本原因,那看起来很简单的一个i++为什么会有这种问题?这里就简单的从java内存模型(JMM)来了解一下,首先JMM规定,每一个线程运行时都会有一个工作内存,然后变量i是存储在主内存的,每次线程在计算数据的时候都要去主内存中获取当前变量的值,那么简单的来说,就是一个线程将变量i计算得到结果后,还没有将这个数据刷新到主内存,在这个时候,其他的线程已经获取到了原来的值,换句话说,本线程中获取到的数据是否是最新的,这个是不知道的。但是这只是从JMM角度来简单的说一下,i++这个看似简单的操作其实包含了三个操作,获取i的值,对i进行自增,然后对i进行赋值。就是在这几个操作中,其他的线程会有很多的时间来做很多的事情,那有人会问,是不是将这个i++操作同步就可以了?是的,那该如何同步呢?

有人说用volatile来修饰一下变量i不就可以了么?是的,javavolatile这个关键字确实是提供了一个同步的功能,但是为什么在这里修改一下还是没有效果呢?原因就在于如果一个变量用volatile修饰之后,只是会让其他的线程立即能够知道当前变量的值是多少,这里就叫做可见性,但是还是解决不了i++这几个操作的问题,那如何处理,又有人提出用synchronized这个关键字,不得不承认,这个关键字确实很强大,是能够解决这个问题,那我们有没有考虑过这个为什么可以解决这个问题,是如何解决的,那还是简单的说一下,首先synchronized是属于JVM级别的,有这个关键字的方法或者代码块,最后会被解释成monitorentermonitorexit指令,这两个字节码都明确需要一个reference类型的参数来指出要锁定或者解锁的对象,像这样:

public synchronized String f(){
    //code
}

synchronized(object){
    //code
}

看到这里,我们应该能明白synchronized为什么可以解决上面程序的问题,但是我们还应该要明确一个概念就是原子性,换句话说,就是我们在处理一些多线程的问题的时候,应该保证一些共享数据的操作是原子性的,这样才能保证正确性,看到这里,相信你也有了一个大概的理解,那我们来总结一下,在处理多线程的问题的时候,哪些点是值得注意的,可见性原子性有序性

어떤 사람들은 변수 i를 수정하기 위해 휘발성을 사용하는 것만으로도 충분하다고 말합니다. 예, java휘발성 키워드는 동기화 기능을 제공하지만 여기서 수정해도 여전히 효과가 없는 이유는 무엇입니까? 그 이유는 변수를 휘발성으로 수정하면 다른 스레드만 현재 변수의 값을 즉시 알 수 있도록 허용하는 것인데 이를 가시성이라고 하지만 여전히 문제를 해결할 수는 없습니다. i++ 코드 작업의 문제를 어떻게 처리할 것인가? 누군가 <code>synchronized 키워드를 사용하자고 제안했습니다. 이 키워드는 실제로 매우 강력하고 이 문제를 해결할 수 있습니다. 이 문제가 왜 해결될 수 있는지, 어떻게 해결할 수 있는지 생각해 본 적이 있나요? 먼저 간단히 설명하자면, synchronized는 JVM 레벨에 속합니다. 키워드는 monitorentermonitorexit 명령어에서 설명됩니다. 두 바이트코드 모두 개체를 나타내기 위해 명시적으로 reference 유형의 매개변수가 필요합니다. 이렇게:

    public String f(String s1, String s2, String s3){
        return s1 + s2 +s3;
    }

이를 보면 synchronized가 위 프로그램의 문제를 해결할 수 있는 이유를 이해할 수 있지만 라는 개념도 명확히 해야 합니다. 원자성. 즉, 일부 멀티 스레드 문제를 다룰 때 정확성을 보장하기 위해 공유 데이터에 대한 일부 작업이 원자성인지 확인해야 합니다. 이해하셨으니 요약하자면 멀티스레딩 문제를 다룰 때 주의할 점, 가시성, 원자성, 질서성, 이러한 몇 가지 사항은 멀티스레딩이 올바른지 확인하기 위한 전제 조건입니다. 순서가 무엇인지에 관해서는 여기에는 논의 범위에 포함되지 않는 메모리 명령의 재정렬이 포함됩니다.

여기서 짚고 넘어가야 할 또 다른 질문은 멀티스레딩 문제를 다룰 때 동기화를 해야 하는지 아니면 잠금을 해야 하는지에 대한 것입니다. 이전에 인터넷에 농담이 있었습니다. 스레딩 문제에 관해서는 때때로 코드가 단일 스레드로 작성되었음을 알 수 있습니다. 물론 이것은 단지 농담이지만 ​​여기서도 볼 수 있습니다. 단일 스레드 프로그램에는 이러한 문제가 없습니까? 대답은 '예'입니다. 단일 스레드에서는 리소스 경쟁 문제가 없으므로 다시 논의할 필요가 없기 때문입니다.

그렇다면 언제 동기화를 사용해야 하고, 언제 사용하지 말아야 할까요? 코드를 살펴보겠습니다

rrreee
이것은 문자열 접합 방법입니다. JVM이 어떻게 하는지 살펴보겠습니다.

관련 추천 :

Java 스레드 동기화 및 동기화 방법에 대한 자세한 설명

🎜Java 동기화 블록 동기화 블록 사용에 대한 자세한 소개🎜🎜

위 내용은 학습 문서: Java의 동기화 정보의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.