불변클래스
불변 클래스 : 한 번 만들어지면(초기화가 끝나면) 인스턴스가 소멸될 때 까지 상태가 바뀌지 않는 것(해당 클래스가 가지고 있는 필드 값)
- 불변 클래스는 가변 클래스보다 설계하고 구현하고 사용하기 쉬우며, 오류가 생길 여지도 적고 훨씬 안전하다.
- 불변 클래스를 만드는 다섯가지 규칙
- 객체의 상태를 변경하는 메서드를 제공하지 않는다.
- 클래스를 확장할 수 없도록 한다.
- 모든 필드를 final로 선언한다.
- 모든 필드를 private로 선언한다.
- 자신 외에는 내부의 가변 컴포넌트에 접근할 수 없도록 한다.
불변 클래스는 가변 클래스보다 설계하고 구현하고 사용하기 쉬우며, 오류가 생길 여지도 적고 훨씬 안전하다.
멀티 스레드 환경에서 스레드 세이프. 값이 변하지 않으니 여러 스레드에서 사용할 때 캐시해서 사용한다.
객체의 상태를 변경하는 메서드를 제공하지 않는다.
클래스를 확장할 수 없도록 한다.
모든 필드를 final로 선언한다.
모든 필드를 priavte로 선언한다.
이전 챕터에서 나왔듯이 외부 클래스에서 필드명으로 값에 접근하지 못하게 하고 getter 메서드로 상태값을 받게하는게 유연하게 관리가 가능하다. 필드값이 변경되면 가져다 쓴 모든 클래스 변경이 필요하기 때문
자신 외에는 내부의 가변 컴포넌트에 접근할 수 없도록 한다.
불변 클래스의 장점과 단점
- 함수형 프로그래밍에 적합하다. (피연산자에 함수를 적용한 결과를 반환하지만 피연산자가 바뀌지는 않는다.)
- 불변 객체는 단순하다
- 불변 객체는 근본적으로 스레드 안전하여 따로 동기화할 필요 없다.
- 불변 객체는 안심하고 공유할 수 있다. (상수, public static final)
- 불변 객체 끼리는 내부 데이터를 공유할 수 있다.
- 객체를 만들 때 불변 객체로 구성하면 이점이 많다.
- 실패 원자성을 제공한다.
- 단점) 값이 다르다면 반드시 별도의 객체로 만들어야 한다.
- "다단계 연산"을 제공하거나, "가변 동반 클래스"를 제공하여 대처할 수 있다.
함수형 프로그래밍에 적합하다.
함수형 프로그래밍은 불변성을 지향하는 프로그래밍 언어로 변경 가능한 상태를 최대한 제거하고 Side Effect가 없어야 한다.
불변 객체는 근본적으로 스레드 안전하여 따로 동기화할 필요 없다.
여러 스레드에서 한 인스턴스의 값을 사용하는 경우 실행 순서에 따라 여러 스레드의 값이 물리게 되는 경우가 생길 경우 값이 변경되면 다른 결과값이 나올 수 있는데 불변객체는 그럴 일이 없다.
불변 객체는 안심하고 공유할 수 있는 것도 마찬가지 public static final 정적 필드의 값도 여러 곳에서 공용되어 사용할 목적으로 선언한 필드이지만 불변 객체로 선언한다면 다 같은 값을 사용하게 되니 안심하고 사용할 수 있다.
불변 객체 끼리는 내부 데이터를 공유할 수 있다.
불변객체에서 사용할 값이 레퍼런스 타입이라면 해당하는 객체도 불변객체여야 한다. 가변 객체이면 부르는 모체가 불변객체라고 할지라도 값이 달라질 수 있기 때문
객체를 만들 때 불변 객체로 구성하면 이점이 많다. 값이 바뀌지 않는 구성요소들로 이뤄진 객체라면 그 구조가 아무리 복잡하더라도 불변식을 유지하기 훨씬 수월하기 때문.
실패 원자성을 제공한다. 상태가 절대 변하지 않으니 잠깜이라도 불일치 상태에 빠질 가능성이 없다.
다 비슷한 장점
단점으로 값이 다르면 독립된 객체로 만들어야 하는데 생성 비용이 비싼 객체라면 불변성을 지키기 위해 다른 값을 가진 객체로 매번 생산해야하기 때문이다.
불변 클래스 만들 때 고려할 것
- 상속을 막을 수 있는 또 다른 방법
- private 또는 package-private 생성자 + 정적 팩터리(valueOf)
- 확장이 가능하다. 다수의 package-private 구현 클래스를 만들 수 있다.
- 정적 팩터리를 통해 여러 구현 클래스 중 하나를 활용할 수 있는 유연성을 제공하고 객체 캐싱 기능으로 성능을 향상 시킬수도 있다.
- 재정의가 가능한 클래스는 방어적인 복사를 사용해야한다.
- 모든 "외부에 공개하는" 필드가 final이어야 한다.
- 계산 비용이 큰 값은 해당 값이 필요로 할 때 (나중에) 계산하여 final이 아닌 필드에 캐시해서 쓸 수도 있다.
final과 자바 메모리 모델(JMM)
- JMM
- 자바 메모리 모델은 JVM의 메모리 구조가 아니다
- 적법한(legal) 프로그램을 실행 규칙
- 메모리 모델이 허용하는 범위 내에서 프로그램을 어떻게 실행하든 구현체(JVM)의 자유다. (이 과정에서 실행 순서가 바뀔 수도 있다.)
- 어떤 인스턴스의 final 변수를 초기화 하기 전까지 해당 인스턴스를 참조하는 모든 쓰레드는 기다려야 한다.(freeze)
- 인스턴스의 값이 반드시 초기화가 이루어지고 사용되어야 할 값들은 final 키워드를 사용해라
https://aroundck.tistory.com/3422
java.util.concurrenet 패키지 : 병행(concurrency) 프로그래밍에 유용하게 사용할 수 있는 유틸리티 묶음
- 병행(Concurrency)와 병렬(Parallelism)의 차이
- 병행은 여러 작업을 번갈아 가며 실행해 마치 동시에 여러 작업을 동시에 처리하듯 보이지만, 실제로는 한번에 오직 한 작업만 실행한다. CPU가 한개여도 가능하다.
- 병렬은 여러 작업을 동시에 처리한다. CPU가 여러개 있어야 가능하다.
- 자바의 concurrent 패키지는 병행 어플리케이션에 유용한 다양한 툴을 제공한다.
- BlockingQueue, Callable, ConcurrentMap, Executor, ExecutorService, Future...
CountDownLatch : 다른 여러 스레드로 실행하는 여러 오퍼레이션이 마칠 때까지 기다릴 때 사용할 수 있는 유틸리티
- 초기화할 때 숫자를 입력하고, await() 메서드를 사용해서 숫자가 0이 될 때까지 기다린다.
- 숫자를 셀 때는 countDown() 메서드를 사용한다.
- 재사용할 수 있는 인스턴스가 아니다. 숫자를 리셋해서 재사용하려면 CyclicBarrier를 사용해야 한다.
- 시작 또는 종료 신호로 사용할 수 있다.
https://www.inflearn.com/course/%EC%9D%B4%ED%8E%99%ED%8B%B0%EB%B8%8C-%EC%9E%90%EB%B0%94-2/dashboard
'개인룸 > 도윤' 카테고리의 다른 글
Item19. 상속을 고려해 설계하고 문서화하라. 그러지 않았다면 상속을 금지하라 (0) | 2023.03.06 |
---|---|
Item18. 상속보다는 컴포지션을 사용하라 (0) | 2023.03.06 |
Item16. public 클래스에서는 public 필드가 아닌 접근자 메서드를 사용하라 (0) | 2023.02.23 |
Item15. 클래스와 멤버의 접근 권한을 최소화하라. (0) | 2023.02.23 |
Item.14 Comparable을 구현할지 고려하라 (0) | 2023.02.12 |