도입

Java 는 “메모리 전체를 하나의 거대한 배열"로 다루는 언어에서는 누릴 수 없는 장점을 갖고 있습니다.

사실 보안적으로는 Java 에서 어떤 일이 일어날 수 있는지에 대해서는 정확히 모르겠습니다만, C, C++ 의 경우는, 메모리를 바이트 배열로 바라보며, 포인터를 통한 접근을 하기 때문에 “권한이 없더라도 즉 할당하지 않은 메모리" 에 대한 접근을 하는 것이 허용되기도 합니다.

Java 에서는 JVM 을 통해 바이트코드를 실행하기 때문에, 할당된 메모리 외부에 대하여 읽고 쓰는 코드에 대한 기본적인 검사를 수행해 줍니다.( 더 자세한 내용은 개인적으로 찾아보면 좋을 것 같슴다.. )

하지만 Java 역시 적절하게 코드가 작성되어있지 않으면 “ 예상하지 못했다고 생각되는 접근, 변경" 이 발생할 것입니다.

적절하지 않은 클라이언트로부터, 클래스를 보호 해야합니다

예시) 클래스 내부 인스턴스 필드가 가변객체인 경우

다음 예시를 살펴봅시다.

public final class Period {
    private final Date start;
    private final Date end;

		public Date start() {
        return this.start;
    }
    public Date end() {
        return this.end;
    }

    public String toString() {
        return start + " - " + end;
    }
}

위와 같이 인스턴스 필드 선언에 final 키워드를 사용하더라도, Date 라는 “가변 객체" 를 사용할 경우 Period 클래스는 불변이 아니다.

가변객체를 사용하며 아래와 같은 상황이 발생한다

현재 스레드에서 생성한 Period 객체를, 커스텀하게 생성한 스레드 풀의 스레드들이 받아서 사용하도록 하였다.

그 결과, Period 의 start 인 Date 의 값이 변경됨을 확인할 수 있다. ——> 불변이 아니라는 것 💥

		@Nested
    @DisplayName("동시성 테스트")
    public class ConcurrentTest {
        private long timeToAdd = 1000L;

				@Test
        @DisplayName("동시에 실행 중인 여러 스레드에서 하나의 Period 를 공유할 경우 예상하지 못한 결과가 발생한다")
        void testFixedThreadPool() throws Exception {
            long startTime = 1000L;

            Period period = new Period(new Date(startTime), new Date(1500));
            Date startDate = period.start();

            runConcurrentTasks(period);

            Assertions.assertThat(period.start())
                    .isEqualTo(startDate);

            Assertions.assertThat(period.start().getTime())
                .isNotEqualTo(startTime); // 현재 스레드에선 startTime 을 변경한적 없음에도 startTime이 달라졌다
        }
	}

위와 같은 경우 어떻게 해야할까?

새로 나온 타입을 사용

Date 를 대체하는 **불변 객체인 LocalDateTime, ZonedDateTime, Instant** 가 새롭게 등장하였으니 이들을 사용하는 것으로 변경할 수 있다.