JavaRush /Java Blog /Random-KO /커피 브레이크 #113. Java의 멀티스레딩에 대해 아마 몰랐을 5가지 기술 부채를 해소하기 위한 1...

커피 브레이크 #113. Java의 멀티스레딩에 대해 아마 몰랐을 5가지 기술 부채를 해소하기 위한 10가지 JetBrains 확장 프로그램

Random-KO 그룹에 게시되었습니다

Java의 멀티스레딩에 대해 아마도 몰랐을 5가지

출처: DZone Thread는 Java 프로그래밍 언어의 핵심입니다. Hello World 프로그램을 실행하는 경우에도 메인 스레드가 필요합니다. 필요한 경우 애플리케이션 코드를 더욱 기능적이고 효율적으로 만들고 싶다면 프로그램에 다른 스레드를 추가할 수 있습니다. 웹 서버에 관해 이야기하고 있다면 수백 개의 요청을 동시에 처리합니다. 이를 위해 여러 스레드가 사용됩니다. 커피 브레이크 #113.  Java의 멀티스레딩에 대해 아마 몰랐을 5가지  기술 부채를 해결하기 위한 10가지 JetBrains 확장 - 1스레드는 의심할 여지없이 유용하지만 스레드를 사용하여 작업하는 것은 많은 개발자에게 어려울 수 있습니다. 이 기사에서는 신규 개발자와 숙련된 개발자가 알지 못할 수도 있는 5가지 멀티스레딩 개념을 공유하겠습니다.

1. 프로그램 순서와 실행 순서가 일치하지 않습니다.

우리는 코드를 작성할 때 우리가 작성한 방식대로 코드가 정확하게 실행될 것이라고 가정합니다. 그러나 실제로는 그렇지 않습니다. Java 컴파일러는 단일 스레드 코드에서 출력이 변경되지 않을 것이라고 판단할 수 있는 경우 실행 순서를 변경하여 최적화할 수 있습니다. 다음 코드 조각을 살펴보세요.
package ca.bazlur.playground;

import java.util.concurrent.Phaser;

public class ExecutionOrderDemo {
    private static class A {
        int x = 0;
    }

    private static final A sharedData1 = new A();
    private static final A sharedData2 = new A();

    public static void main(String[] args) {
        var phaser = new Phaser(3);
        var t1 = new Thread(() -> {
            phaser.arriveAndAwaitAdvance();
            var l1 = sharedData1;
            var l2 = l1.x;
            var l3 = sharedData2;
            var l4 = l3.x;
            var l5 = l1.x;
            System.out.println("Thread 1: " + l2 + "," + l4 + "," + l5);
        });
        var t2 = new Thread(() -> {
            phaser.arriveAndAwaitAdvance();
            var l6 = sharedData1;
            l6.x = 3;
            System.out.println("Thread 2: " + l6.x);
        });
        t1.start();
        t2.start();
        phaser.arriveAndDeregister();
    }
}
이 코드는 간단해 보입니다. 두 개의 스레드를 사용하는 두 개의 공유 데이터 인스턴스( sharedData1sharedData2 )가 있습니다 . 코드를 실행하면 다음과 같은 출력이 나올 것으로 예상됩니다.
스레드 2: 3 스레드 1: 0,0,0
그러나 코드를 여러 번 실행하면 다른 결과가 표시됩니다.
스레드 2: 3 스레드 1: 3,0,3 스레드 2: 3 스레드 1: 0,0,3 스레드 2: 3 스레드 1: 3,3,3 스레드 2: 3 스레드 1: 0,3,0 스레드 2 : 3 스레드 1: 0,3,3
이 모든 스트림이 여러분의 컴퓨터에서 정확히 이와 같이 재생된다는 말은 아니지만 전적으로 가능합니다.

2. Java 스레드 수는 제한되어 있습니다.

Java에서 스레드를 생성하는 것은 쉽습니다. 그러나 이것이 우리가 원하는 만큼 많이 만들 수 있다는 의미는 아닙니다. 스레드 수는 제한되어 있습니다. 다음 프로그램을 사용하면 특정 시스템에서 생성할 수 있는 스레드 수를 쉽게 확인할 수 있습니다.
package ca.bazlur.playground;

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.LockSupport;

public class Playground {
    public static void main(String[] args) {
        var counter = new AtomicInteger();
        while (true) {
            new Thread(() -> {
                int count = counter.incrementAndGet();
                System.out.println("thread count = " + count);
                LockSupport.park();
            }).start();
        }
    }
}
위 프로그램은 매우 간단합니다. 루프에서 스레드를 생성한 다음 이를 파킹합니다. 즉, 스레드는 나중에 사용할 수 없도록 비활성화되지만 시스템 호출을 수행하고 메모리를 할당합니다. 프로그램은 더 이상 스레드를 생성할 수 없을 때까지 계속해서 스레드를 생성한 다음 예외를 발생시킵니다. 우리는 프로그램이 예외를 던질 때까지 받게 될 숫자에 관심이 있습니다. 내 컴퓨터에서는 4065개의 스레드만 생성할 수 있었습니다.

3. 스레드가 너무 많다고 해서 더 나은 성능이 보장되는 것은 아닙니다.

Java에서 스레드를 쉽게 만들면 애플리케이션 성능이 향상될 것이라고 믿는 것은 순진한 생각입니다. 불행하게도 이 가정은 오늘날 Java가 제공하는 전통적인 멀티스레딩 모델에서는 잘못된 것입니다. 실제로 스레드가 너무 많으면 애플리케이션 성능이 저하될 수 있습니다. 먼저 다음 질문을 해보겠습니다. 애플리케이션 성능을 최대화하기 위해 생성할 수 있는 최적의 최대 스레드 수는 얼마입니까? 글쎄요, 대답은 그렇게 간단하지 않습니다. 그것은 우리가 하는 일의 유형에 따라 크게 달라집니다. 여러 개의 독립적인 작업이 있고 모두 계산 작업이고 외부 리소스를 차단하지 않는 경우 스레드 수가 많아도 성능이 크게 향상되지 않습니다. 반면에 8코어 프로세서가 있는 경우 최적의 스레드 수는 (8 + 1)이 될 수 있습니다. 이러한 경우 Java 8에 도입된 병렬 스레드를 사용할 수 있습니다. 기본적으로 병렬 스레드는 공유 Fork/Join 풀을 사용합니다. 사용 가능한 프로세서 수와 동일한 스레드를 생성하므로 집중적으로 작업하기에 충분합니다. 아무것도 차단되지 않은 CPU 집약적 작업에 더 많은 스레드를 추가해도 성능이 향상되지 않습니다. 오히려 자원을 낭비할 뿐입니다. 메모. 추가 스레드를 갖는 이유는 계산 집약적인 스레드라도 때때로 페이지 오류를 일으키거나 다른 이유로 일시 중단되기 때문입니다. (참조: 실제 Java 병렬 처리 , Brian Goetz, 170페이지) 그러나 예를 들어 작업이 I/O 바인딩되어 있다고 가정합니다. 이 경우 외부 통신(예: 데이터베이스, 기타 API)에 의존하므로 더 많은 수의 스레드가 의미가 있습니다. 그 이유는 스레드가 Rest API를 기다리는 동안 다른 스레드가 계속 작업할 수 있기 때문입니다. 이제 다시 질문할 수 있습니다. 이러한 경우에는 스레드가 너무 많습니까? 상황에 따라 다릅니다. 모든 경우에 맞는 완벽한 숫자는 없습니다. 따라서 특정 워크로드와 애플리케이션에 가장 적합한 것이 무엇인지 알아보려면 적절한 테스트를 수행해야 합니다. 가장 일반적인 시나리오에서는 일반적으로 작업 세트가 혼합되어 있습니다. 그리고 그러한 경우에는 모든 것이 완료됩니다. Brian Goetz는 자신의 저서 "Java Concurrency in Practice"에서 대부분의 경우에 사용할 수 있는 공식을 제안했습니다. 스레드 수 = 사용 가능한 코어 수 * (1 + 대기 시간 / 서비스 시간) 대기 시간은 HTTP 응답 대기, 잠금 획득 등 IO일 수 있습니다. 서비스 시간(서비스 시간)은 HTTP 응답 처리, 마샬링/마샬링 해제 등의 계산 시간입니다. 예를 들어 애플리케이션은 API를 호출한 다음 이를 처리합니다. 애플리케이션 서버에 8개의 프로세서가 있고 평균 API 응답 시간은 100ms이고 응답 처리 시간은 20ms인 경우 이상적인 스레드 크기는 다음과 같습니다.
N = 8 * ( 1 + 100/20) = 48
그러나 이는 지나치게 단순화된 것입니다. 적절한 테스트는 숫자를 결정하는 데 항상 중요합니다.

4. 멀티스레딩은 병렬성이 아니다

때때로 멀티스레딩과 병렬성을 같은 의미로 사용하지만 이는 더 이상 완전히 관련이 없습니다. Java에서는 스레드를 사용하여 두 가지를 모두 달성하지만 두 가지가 다릅니다. “프로그래밍에서 멀티스레딩은 실행 중인 프로세스에 관계없이 특별한 경우이며 병렬성은 (아마도 관련이 있는) 계산을 동시에 실행하는 것입니다. 멀티스레딩은 동시에 많은 것들과 상호작용하는 것입니다 . 동시성은 동시에 많은 일을 하는 것 입니다 .” Rob Pike가 제시한 위의 정의는 매우 정확합니다. 완전히 독립적인 작업이 있고 별도로 계산할 수 있다고 가정해 보겠습니다. 이 경우 이러한 작업을 병렬이라고 하며 Fork/Join 풀 또는 병렬 스레드를 사용하여 실행할 수 있습니다. 반면에 작업이 많으면 그 중 일부는 다른 작업에 종속될 수 있습니다. 우리가 구성하고 구조화하는 방식을 멀티스레딩이라고 합니다. 그것은 구조와 관련이 있습니다. 특정 결과를 얻기 위해 하나의 작업을 더 빨리 완료할 필요 없이 여러 작업을 동시에 수행하고 싶을 수도 있습니다.

5. Project Loom을 사용하면 수백만 개의 스레드를 생성할 수 있습니다.

이전 시점에서 나는 더 많은 스레드를 갖는다고 해서 애플리케이션 성능이 향상되는 것은 아니라고 주장했습니다. 그러나 마이크로서비스 시대에는 특정 작업을 완료하기에는 너무 많은 서비스와 상호 작용합니다. 이러한 시나리오에서 스레드는 대부분의 경우 차단된 상태로 유지됩니다. 최신 OS는 수백만 개의 열린 소켓을 처리할 수 있지만 스레드 수에 제한이 있기 때문에 많은 통신 채널을 열 수는 없습니다. 하지만 수백만 개의 스레드를 생성하고 각 스레드가 개방형 소켓을 사용하여 외부 세계와 통신한다면 어떻게 될까요? 이를 통해 애플리케이션 처리량이 확실히 향상될 것입니다. 이 아이디어를 지원하기 위해 Java에는 Project Loom이라는 계획이 있습니다. 이를 사용하면 수백만 개의 가상 스레드를 만들 수 있습니다. 예를 들어, 다음 코드 조각을 사용하여 내 컴퓨터에 450만 개의 스레드를 생성할 수 있었습니다.
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.LockSupport;

public class Main {
    public static void main(String[] args) {
        var counter = new AtomicInteger();

        // 4_576_279
        while (true) {
            Thread.startVirtualThread(() -> {
                int count = counter.incrementAndGet();
                System.out.println("thread count = " + count);
                LockSupport.park();
            });
        }
    }
}
이 프로그램을 실행하려면 Java 18이 설치되어 있어야 하며 여기에서 다운로드할 수 있습니다 . 다음 명령을 사용하여 코드를 실행할 수 있습니다. java --source 18 --enable-preview Main.java

기술 부채를 해소하기 위한 10가지 JetBrains 확장 프로그램

출처: DZone 많은 개발팀은 마감일을 준수해야 한다는 엄청난 압박감을 느낍니다. 이 때문에 코드베이스를 수정하고 정리할 시간이 부족한 경우가 많습니다. 때로는 이러한 상황에서 기술 부채가 빠르게 누적됩니다. 편집기 확장은 이 문제를 해결하는 데 도움이 될 수 있습니다. 기술 부채를 해결하기 위한 최고의 JetBrains 확장 프로그램(Java 지원 포함) 10가지를 살펴보겠습니다. 커피 브레이크 #113.  Java의 멀티스레딩에 대해 아마 몰랐을 5가지  기술 부채를 해소하기 위한 10가지 JetBrains 확장 - 2

리팩토링 및 기술 부채 도구

1. 리팩터인사이트

RefactorInsight는 리팩토링에 대한 정보를 제공하여 IDE의 코드 변경 사항에 대한 가시성을 향상시킵니다.
  1. 확장은 병합 요청의 리팩토링을 정의합니다.
  2. 리팩토링이 포함된 커밋을 표시합니다.
  3. Git 로그 탭에서 선택한 특정 커밋의 리팩토링을 보는 데 도움이 됩니다.
  4. 클래스, 메소드 및 필드의 리팩토링 기록을 표시합니다.

2. IDE의 Stepsize 문제 추적기

Stepsize는 개발자를 위한 훌륭한 이슈 추적기입니다. 이 확장은 엔지니어가 더 나은 TODO 및 코드 주석을 작성할 뿐만 아니라 기술 부채, 리팩토링 등의 우선순위를 지정하는 데 도움이 됩니다.
  1. Stepsize를 사용하면 편집기에서 바로 코드로 작업을 만들고 볼 수 있습니다.
  2. 작업 중인 기능에 영향을 미치는 문제를 찾아보세요.
  3. Jira, Asana, Linear, Azure DevOps 및 GitHub 통합을 사용하여 스프린트에 문제를 추가하세요.

3. 뉴렐릭 코드스트림

New Relic CodeStream은 코드를 논의하고 검토하기 위한 개발자 협업 플랫폼입니다. GitHub, BitBucket 및 GitLab의 풀 요청, Jira, Trello, Asana 및 기타 9개의 문제 관리를 지원하고 코드 토론을 제공하여 모두 하나로 묶습니다.
  1. GitHub에서 풀 요청을 생성, 검토 및 병합합니다.
  2. 예비 코드 검토를 통해 진행 중인 작업에 대한 피드백을 받으세요.
  3. 팀원들과 코드 문제에 대해 논의합니다.

TODO 및 댓글

4. 댓글 하이라이터

이 플러그인을 사용하면 주석 줄과 언어 키워드에 대한 사용자 지정 강조 표시를 만들 수 있습니다. 플러그인에는 주석 줄을 강조 표시하기 위한 사용자 정의 토큰을 정의하는 기능도 있습니다.

5. 더 나은 댓글

Better Comments 확장 프로그램을 사용하면 코드에서 더 명확한 주석을 작성할 수 있습니다. 이 확장을 사용하면 주석을 다음과 같이 분류할 수 있습니다.
  1. 경고.
  2. 요청.
  3. 할 것.
  4. 기본적인 순간.

버그 및 보안 취약점

6.소나린트 _

SonarLint를 사용하면 코드 문제가 발생하기 전에 문제를 해결할 수 있습니다. 맞춤법 검사기로도 사용할 수 있습니다. SonarLint는 코드를 작성하는 동안 버그와 보안 취약성을 강조하고 명확한 수정 지침을 제공하므로 코드가 커밋되기 전에 이를 수정할 수 있습니다.

7. 스팟버그

SpotBugs 플러그인은 IntelliJ IDEA의 Java 코드에서 버그를 찾기 위한 정적 바이트코드 분석을 제공합니다. SpotBugs는 정적 분석을 사용하여 널 포인터 역참조, 무한 재귀 루프, Java 라이브러리 오용 및 교착 상태와 같은 400개 이상의 버그 패턴을 찾는 Java용 결함 감지 도구입니다. SpotBugs는 대규모 애플리케이션에서 수백 개의 심각한 결함을 식별할 수 있습니다(일반적으로 주석 처리되지 않은 원시 명령문의 1000-2000줄당 약 1개의 결함).

8. Snyk 취약점 스캐너

Snyk의 Vulnerability Scanner는 프로젝트의 보안 취약성과 코드 품질 문제를 찾아 수정하는 데 도움이 됩니다.
  1. 보안 문제를 찾아 해결합니다.
  2. 다양한 유형의 문제 목록을 범주별로 나누어 봅니다.
  3. 문제 해결 팁을 표시합니다.

9. 너비가 0인 문자 찾기

이 플러그인은 소스 코드 및 리소스에서 보이지 않는 너비 0 문자와 관련된 찾기 어려운 오류의 검사 및 감지 기능을 향상시킵니다. 사용 시에는 "0 너비 유니코드 문자" 확인이 활성화되어 있는지 확인하세요.

10.코드MR _

CodeMR은 소프트웨어 회사가 더 나은 코드와 프로그램을 개발하는 데 도움이 되는 소프트웨어 품질 및 정적 코드 분석 도구입니다. CodeMR은 패키지 구조, 트리 맵, Sunburst, 종속성 및 그래프 보기와 같은 다양한 보기에서 코드 메트릭과 높은 수준의 품질 특성(결합, 복잡성, 응집력 및 크기)을 시각화합니다.
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION