자바 (25)

💻 Programming/Java

[Java] 스트림을 이용한 소수 구하기

요즘 이펙티브 자바 Third 에디션 책을 동네 도서관에서 대여해서 읽고있습니다.

스트림 병렬화에 대한 글을 읽다가 소수구하는 로직을 스트림으로 작성한 부분을 보게되었습니다.

소수구하기 로직은 이직준비 할 때나 다시 들여다볼만한거라 오래전에 for-loop 로 구현해본 기억만 있다보니 신선하게 느껴졌네요.

아직도 많은 블로그들에서 for-loop를 이용한 방법들만 많이 소개하고 있기도 하고해서 포스팅 주제로 삼아봤습니다. 

개인적인 기록도 할겸...

책을 읽고 새로 알게된 부분은 스트림에 대한 부분도 있지만 이미 BigInteger 클래스에 isProbablePrime 이란 메서드가 있었다는 겁니다..

 

아래는 특정 숫자 n 까지 소수가 몇 개인지를 출력하고, 그 목록도 출력하는 것을 테스트한 코드입니다.

public static void main(String[] args) {
    int n = (int) Math.pow(10, 8);
    // n 까지의 수 중에 소수의 개수 출력하기
    long cnt = LongStream.rangeClosed(2, n)
    	    .parallel()
            .mapToObj(BigInteger::valueOf)
            .filter(i -> i.isProbablePrime(50))
            .count();
    System.out.println(cnt);

    // n 까지의 수 중에 소수 목록 출력하기
    System.out.println(LongStream.rangeClosed(2, n)
            .mapToObj(BigInteger::valueOf)
            .filter(i -> i.isProbablePrime(50))
            .collect(Collectors.toList()));
}

LongStream을 이용하여 숫자의 범위를 정하고 mapToObj 를 이용하여 BigInteger로 변형한뒤 BigInteger.isProbablePrime(int certainty) 메서드를 필터로 전달하여 소수를 구하고 있습니다.

BigInteger.isProbablePrime(int certainty) 메서드는 소수를 구하기위해 내부적으로 밀러-라빈(Miller-Rabin) 테스트와 루카스-레머(Lucas-Lehmer) 테스트를 사용하고 있고요. 여기서 사용된 밀러라빈 테스트는 DSA(Digital Signiture Algorithm) 스펙 (NIST FIPS 186-2)을 기반으로 했다고 합니다. 이 스펙은 파일로 첨부하니 관심있으신 분들은 다운받아 보셔도 될 것 같네요. 

 

fips186-2.pdf
0.35MB

 

참고로 .parallel() 은 스트림에서 사용할 때 매우 주의를 요하는 기능입니다. 책에서는 이렇게 얘기합니다. Stream.iterate 를 데이터 소스로 이용하거나 중간 연산으로 limit 을 사용하는 스트림 파이프라인에서는 parallel을 이용한 성능개선을 기대할 수 없으며 오히려 안좋아질 수도 있다고 말이죠. 실제로 운영환경에서 저것 때문에 이슈가 발생한 적도 있었습니다. 그냥 무한루프에 빠진것처럼 쓰레드 하나가 먹통이 되어버리더군요. 스트림에서 병렬연산에 적합한 적은 reduce, min, max, count, sum 등의 연산이며, collect처럼 가변축소를 수행하는 메서드는 병렬연산에 적합하지 않다고 합니다. 참고하시기 바랍니다.

자바에서 비동기 호출하기 (AsyncRestTemplate, ListenableFuture)

안녕하세요, 최근에 관리자용 앱을 개선하다가 비동기 처리에 대해서 공유하고 싶은 것이 있어 포스팅을 작성합니다.

제가 관리중인 관리자용 앱은 Spring Framework 4, Java 8, Bootstrap 3 기반으로 작성되어있습니다.

오래된 라이브러리들을 업그레이드 하고 싶지만 메인 업무가 아니다보니 짬날때 조금씩 업그레이드 해주고 있는데 부트스트랩이나 스프링 버전을 올리기엔 작업량이 많아보여서 안건드리고 있네요.

 

아무튼 자바에서 비동기로 호출을 하는 방법은 크게 두 가지가 있는 것 같습니다.

 

첫 번째는 callee 메서드 쪽에서 @Async 를 붙여서 비동기로 동작하게 하는 방법이 있고요

이 방법은 callee가 외부 팀이거나 외부 회사일 경우 불가능하거나 일이 빨리 진행하기 어려울 수 있습니다.

굳이 특별한 이유가 있지 않은이상 callee쪽에 요청을 할 필요는 전혀 없습니다.

하지만 callee가 내부에 있다면 아키텍처 구조상 이 방법을 선택할 수도 있습니다.

 

두 번째는 caller가 호출방식을 직접 비동기로 호출하는 방법입니다.

callee가 어떻게 처리하던지 caller는 신경쓸 필요가 없죠. 

단지 응답만 잘 받아서 처리해주면 됩니다.

 

오늘 소개해 드릴 내용은 두 번째 방식인 caller 입장에서 비동기로 호출하는 방법입니다.

스프링을 사용하신다면 API 호출하실 때 RestTemplate을 사용하실 겁니다.

 

근데 스프링에서는 비동기 호출을 위해서 이미 AsyncRestTemplate 을 제공하고 있습니다.

AsyncRestTemplate 을 이용해서 API를 호출하는 방법은 RestTemplate과 다를게 없죠.

그리고 당연히도 응답을 기다리지 않고 다음 프로세스를 처리하게 됩니다.

그리고 그 응답은 ListenableFuture<ResponseEntity<T>> 타입으로 받습니다.

간단한 예제를 한번 보겠습니다.

 

    // Autowired로 주입된 상태라 가정합니다.
    private final AsyncRestTemplate asyncRestTemplate;
	
    public void test() {
        URI uri = UriComponentsBuilder.fromUriString("http://localhost")
                .path("/test")
                .build()
                .toUri();

        HttpHeaders headers = new HttpHeaders();
        headers.add(HttpHeaders.CONTENT_TYPE, "application/json;charset=UTF-8");

        HttpEntity<String> requestEntity = new HttpEntity<>(headers);
        HttpMethod httpMethod = HttpMethod.POST;

        ListenableFuture<ResponseEntity<Void>> res = 
        	asyncRestTemplate.exchange(uri, httpMethod, requestEntity, Void.class);
        log.info("호출 성공!!");
    }

위 코드는 http://localhost/test 를 POST 방식으로 호출하고 있습니다. 헤더에 application/json;charset=UTF-8 정보도 넣어주고 있고요 응답메시지에 대해서는 Void로 처리하고 있습니다. 어떤 메시지를 응답으로 주던지 신경안쓴다는 거겠죠.

그리고 호출에 대한 결과를 ListenableFuture<ResponseEntity<Void>> res 에 받게 됩니다.

하지만 응답을 받기 전에 호출하자마자 호출 성공!! 로그를 출력하게 됩니다.

 

그러면 그렇게 받은 응답의 결과에 따라 정상과 실패를 구분해서 예외처리를 해줘야 할텐데 그건 어떻게 할까요?

res 에 callback 함수를 넣어주면 됩니다.

콜백을 추가한 예제를 보겠습니다.

 

    // Autowired로 주입된 상태라 가정합니다.
    private final AsyncRestTemplate asyncRestTemplate;

    public void test() {
        URI uri = UriComponentsBuilder.fromUriString("http://localhost")
                .path("/test")
                .build()
                .toUri();

        HttpHeaders headers = new HttpHeaders();
        headers.add(HttpHeaders.CONTENT_TYPE, "application/json;charset=UTF-8");

        HttpEntity<String> requestEntity = new HttpEntity<>(headers);
        HttpMethod httpMethod = HttpMethod.POST;

        ListenableFuture<ResponseEntity<Void>> res = asyncRestTemplate.exchange(uri, httpMethod, requestEntity, Void.class);
        res.addCallback(new ListenableFutureCallback<ResponseEntity<Void>>() {
            @Override
            public void onFailure(Throwable th) {
                log.error("실패");
            }

            @Override
            public void onSuccess(ResponseEntity<Void> voidResponseEntity) {
                if (HttpUtil.isNot2xxSuccessful(voidResponseEntity)) {
                    log.error("실패, 응답코드:{}", voidResponseEntity.getStatusCodeValue();
                } else {
                    log.info("성공");
                    // TODO: 추가 작업
                }
            }
        });

    }

여기서는 annonymous ListenableFutureCallback 클래스를 만들어서 addCallback 메서드에 넘겨주었습니다.

onFailure 와 onSuccess 메서드를 구현해주면 되는데요 이때 주의할 점이 하나 있습니다.

onSuccess 메서드가 호출되는 케이스가 2xx 성공인 케이스만이 아니라는 점입니다.

4xx 케이스도 onSuccess 메서드를 호출하게 됩니다.

onFailure는 SocketTimeout과 같은 예외가 발생하면 호출됩니다.

따라서 실질적으로 우리가 원하는 성공 은 response entity에서 응답코드로 확인해줘야 합니다.

 

참고로 위 코드에서 HttpUtil.isNot2xxSuccessful(voidResponseEntity) 메서드는 아래처럼 코딩되어 있습니다.

public class HttpUtil {

    public static boolean is2xxSuccessful(ResponseEntity responseEntity) {
        return HttpStatus.Series.valueOf(responseEntity.getStatusCodeValue())
        	.equals(HttpStatus.Series.SUCCESSFUL);
    }

    public static boolean isNot2xxSuccessful(ResponseEntity responseEntity) {
        return !is2xxSuccessful(responseEntity);
    }
}

ListenableFuture<ResponseEntity<T>> 에서 제공하는 addCallback 메서드 시그니처는 아래 두 가지가 있습니다.

 

void addCallback(ListenableFutureCallback<? super T> var1);
void addCallback(SuccessCallback<? super T> var1, FailureCallback var2);

 

위 예제에서는 첫 번째 addCallback 메서드를 사용했습니다만, 만약 SuccessCallback와 FailureCallback을 나눠서 구현하여 사용하고 싶다면 각각 구현해서 addCallback 메서드에 파라미터로 전달해주셔도 됩니다.

 

추가로 AsyncRestTemplate 을 스프링에서 제공해주는 기본 클래스를 사용해도 되지만 타임아웃 등 설정을 바꿔서 사용해야한다면 아래 코드를 참고하시면 도움이 되실겁니다.

    @Bean
    public AsyncRestTemplate asyncRestTemplate2() {
        SimpleAsyncTaskExecutor simpleAsyncTaskExecutor = new SimpleAsyncTaskExecutor();
        simpleAsyncTaskExecutor.setTaskDecorator(new MdcTaskDecorator());

        SimpleClientHttpRequestFactory simpleClientHttpRequestFactory = new SimpleClientHttpRequestFactory();
        simpleClientHttpRequestFactory.setConnectTimeout(30_000);    // 밀리초 단위
        simpleClientHttpRequestFactory.setReadTimeout(30_000);       // 밀리초 단위
        simpleClientHttpRequestFactory.setTaskExecutor(simpleAsyncTaskExecutor);

        AsyncRestTemplate asyncRestTemplate = new AsyncRestTemplate(simpleClientHttpRequestFactory);

        return asyncRestTemplate;
    }

    static class MdcTaskDecorator implements TaskDecorator {

        @Override
        public Runnable decorate(Runnable runnable) {
            // Web thread context
            Map<String, String> contextMap = MDC.getCopyOfContextMap();
            return () -> {
                try {
                    // @Async thread context
                    MDC.setContextMap(contextMap);
                    runnable.run();
                } finally {
                    MDC.clear();
                }
            };
        }
    }

 

이상으로 AsyncRestTemplate을 이용하여 자바에서 비동기 호출하기에 대해서 알아봤습니다.

 

하지만 AsyncRestTemplate은 Spring 5로 넘어가면서 deprecated 되었고, WebClient를 사용하도록 권장하고 있습니다.

Deprecated as of Spring 5.0, in favor of org.springframework.web.reactive.function.client.WebClient

WebClient에 대해서는 다음 포스팅에서 다루도록 하겠습니다.

 

오늘도 즐프행프하세요~

 

 

§ 쓰레드 기본 내용에 대해서는 [Java] 멀티쓰레드를 참고하세요.

 

ThreadPoolExecutor 를 이용하여 멀티쓰레드 구현하기

java.util.concurrent 패키지는 동시성 프로그래밍 관련하여 유용한 기능들을 모아둔 패키지입니다.

여기에는 ThreadPoolExecutor가 있는데 이것을 이용하면 손쉽게 멀티쓰레드를 구현할 수 있습니다.

우선 생성자에 어떤 것들이 있는지 확인해보겠습니다.

ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue)

ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, RejectedExecutionHandler handler)

ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, ThreadFactory threadFactory)

ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)


기본적으로 corePoolSize, maximumPoolSize, keepAliveTime, timeUnit 그리고 workQueue를 입력받고 있네요.

각 항목이 의미하는 바가 뭔지 알아보겠습니다. java doc에는 아래와 같이 설명이 나와있습니다.

* @param corePoolSize the number of threads to keep in the pool, even if they are idle, unless {@code allowCoreThreadTimeOut} is set

* @param maximumPoolSize the maximum number of threads to allow in the pool

* @param keepAliveTime when the number of threads is greater than the core, this is the maximum time that excess idle threads will wait for new tasks before terminating.

* @param unit the time unit for the {@code keepAliveTime} argument

* @param workQueue the queue to use for holding tasks before they are executed.


간단히 말하면 corePoolSize는 쓰레드 풀의 기본 사이즈로 몇 개의 쓰레드를 pool에 가지고 있을지에 대한 값이고, maximumPoolSize는 쓰레드 풀의 max size로 이 사이즈를 넘어가면 RejectedExecutionException이 발생하게 됩니다. keepAliveTime은 idle 쓰레드의 keep alive time이며, timeUnit은 keepAliveTime의 시간단위를, 그리고 workQueue는 corePoolSize를 넘어서는 쓰레드들을 queueing 처리하기 위해 사용됩니다.

 

그럼 이제 간단한 예제 코드를 한번 보도록 하겠습니다.

    public static void main(String[] args) throws InterruptedException {

        BlockingQueue<Runnable> blockingQueue = new ArrayBlockingQueue<>(1);
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(100, 100, 10, TimeUnit.SECONDS, blockingQueue);

        Runnable task = new Task();
        for (int i = 0; i < 100; i++) {
            threadPoolExecutor.execute(task);
        }
        System.out.println("쓰레드 콜 종료");
    }
    
    static class Task implements Runnable {

        int num = 0;

        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                System.out.println(Thread.currentThread().getName() + ", num=" + num++);
            }
        }
    }

 

위 코드에서 ThreadPoolExecutor의 corePoolSize와 maximumPoolSize를 각각 100, 100 으로 설정을 해주었습니다.

위 코드를 실행하면 100개의 쓰레드가 각각 task를 실행하면서 아래와 같이 출력을 하게 됩니다. (더보기 클릭해서 보세요)

더보기

pool-1-thread-3, num=1
pool-1-thread-3, num=4
pool-1-thread-4, num=3
pool-1-thread-2, num=0
pool-1-thread-2, num=8
pool-1-thread-2, num=9
pool-1-thread-1, num=2
pool-1-thread-6, num=11
pool-1-thread-6, num=13
pool-1-thread-6, num=14
pool-1-thread-7, num=15
pool-1-thread-7, num=17
pool-1-thread-7, num=18
pool-1-thread-7, num=19
pool-1-thread-7, num=20
pool-1-thread-7, num=21
pool-1-thread-2, num=10
pool-1-thread-2, num=24
pool-1-thread-2, num=25
pool-1-thread-2, num=26
pool-1-thread-2, num=27
pool-1-thread-2, num=28
pool-1-thread-2, num=29
pool-1-thread-4, num=7
pool-1-thread-4, num=31
pool-1-thread-4, num=32
pool-1-thread-4, num=33
pool-1-thread-4, num=34
pool-1-thread-4, num=35
pool-1-thread-4, num=36
pool-1-thread-4, num=37
pool-1-thread-4, num=38
pool-1-thread-3, num=6
pool-1-thread-3, num=39
pool-1-thread-3, num=40
pool-1-thread-3, num=41
pool-1-thread-3, num=42
pool-1-thread-3, num=43
pool-1-thread-3, num=44
pool-1-thread-3, num=45
pool-1-thread-10, num=46
pool-1-thread-10, num=47
pool-1-thread-5, num=5
pool-1-thread-5, num=49
pool-1-thread-11, num=50
pool-1-thread-11, num=52
pool-1-thread-11, num=53
pool-1-thread-11, num=54
pool-1-thread-11, num=56
pool-1-thread-11, num=57
pool-1-thread-11, num=58
pool-1-thread-11, num=59
pool-1-thread-11, num=60
pool-1-thread-11, num=61
pool-1-thread-13, num=62
pool-1-thread-13, num=63
pool-1-thread-13, num=64
pool-1-thread-14, num=65
pool-1-thread-14, num=67
pool-1-thread-10, num=48
pool-1-thread-15, num=69
pool-1-thread-15, num=71
pool-1-thread-15, num=72
pool-1-thread-15, num=73
pool-1-thread-15, num=74
pool-1-thread-15, num=75
pool-1-thread-15, num=76
pool-1-thread-9, num=30
pool-1-thread-9, num=79
pool-1-thread-9, num=80
pool-1-thread-9, num=81
pool-1-thread-9, num=82
pool-1-thread-9, num=83
pool-1-thread-9, num=84
pool-1-thread-9, num=85
pool-1-thread-9, num=86
pool-1-thread-9, num=87
pool-1-thread-7, num=23
pool-1-thread-7, num=89
pool-1-thread-7, num=90
pool-1-thread-7, num=91
pool-1-thread-8, num=22
pool-1-thread-8, num=92
pool-1-thread-8, num=93
pool-1-thread-8, num=94
pool-1-thread-8, num=96
pool-1-thread-8, num=97
pool-1-thread-8, num=98
pool-1-thread-8, num=99
pool-1-thread-8, num=100
pool-1-thread-6, num=16
pool-1-thread-1, num=12
pool-1-thread-1, num=104
pool-1-thread-1, num=105
pool-1-thread-1, num=106
pool-1-thread-1, num=108
pool-1-thread-1, num=109
pool-1-thread-1, num=110
pool-1-thread-1, num=111
pool-1-thread-6, num=103
pool-1-thread-6, num=113
pool-1-thread-6, num=114
pool-1-thread-6, num=115
pool-1-thread-6, num=116
pool-1-thread-6, num=117
pool-1-thread-8, num=102
pool-1-thread-19, num=101
pool-1-thread-19, num=120
pool-1-thread-18, num=95
pool-1-thread-18, num=123
pool-1-thread-18, num=124
pool-1-thread-18, num=125
pool-1-thread-18, num=126
pool-1-thread-18, num=127
pool-1-thread-18, num=128
pool-1-thread-18, num=129
pool-1-thread-18, num=130
pool-1-thread-18, num=131
pool-1-thread-17, num=88
pool-1-thread-25, num=133
pool-1-thread-25, num=135
pool-1-thread-25, num=136
pool-1-thread-25, num=137
pool-1-thread-26, num=138
pool-1-thread-26, num=140
pool-1-thread-26, num=141
pool-1-thread-15, num=78
pool-1-thread-15, num=143
pool-1-thread-15, num=144
pool-1-thread-27, num=145
pool-1-thread-27, num=146
pool-1-thread-16, num=77
pool-1-thread-10, num=70
pool-1-thread-10, num=150
pool-1-thread-10, num=151
pool-1-thread-10, num=152
pool-1-thread-10, num=154
pool-1-thread-10, num=155
pool-1-thread-10, num=156
pool-1-thread-14, num=68
pool-1-thread-14, num=157
pool-1-thread-14, num=159
pool-1-thread-14, num=160
pool-1-thread-14, num=161
pool-1-thread-14, num=162
pool-1-thread-13, num=66
pool-1-thread-13, num=164
pool-1-thread-13, num=165
pool-1-thread-32, num=166
pool-1-thread-12, num=55
pool-1-thread-33, num=169
pool-1-thread-5, num=51
pool-1-thread-5, num=172
pool-1-thread-5, num=174
pool-1-thread-5, num=175
pool-1-thread-5, num=176
pool-1-thread-5, num=177
pool-1-thread-5, num=179
pool-1-thread-5, num=180
pool-1-thread-33, num=171
pool-1-thread-33, num=181
pool-1-thread-33, num=182
pool-1-thread-33, num=183
pool-1-thread-12, num=170
pool-1-thread-12, num=185
pool-1-thread-12, num=186
pool-1-thread-12, num=188
pool-1-thread-12, num=189
pool-1-thread-12, num=190
pool-1-thread-12, num=191
pool-1-thread-12, num=192
pool-1-thread-12, num=194
pool-1-thread-38, num=195
pool-1-thread-32, num=168
pool-1-thread-32, num=197
pool-1-thread-32, num=198
pool-1-thread-32, num=199
pool-1-thread-32, num=201
pool-1-thread-32, num=202
pool-1-thread-32, num=203
pool-1-thread-13, num=167
pool-1-thread-40, num=205
pool-1-thread-40, num=207
pool-1-thread-40, num=208
pool-1-thread-40, num=209
pool-1-thread-40, num=210
pool-1-thread-40, num=212
pool-1-thread-40, num=213
pool-1-thread-40, num=214
pool-1-thread-14, num=163
pool-1-thread-14, num=217
pool-1-thread-43, num=218
pool-1-thread-43, num=219
pool-1-thread-43, num=220
pool-1-thread-43, num=221
pool-1-thread-43, num=222
pool-1-thread-31, num=162
pool-1-thread-30, num=158
pool-1-thread-30, num=226
pool-1-thread-30, num=227
pool-1-thread-30, num=228
pool-1-thread-30, num=229
pool-1-thread-45, num=230
pool-1-thread-45, num=232
pool-1-thread-45, num=233
pool-1-thread-45, num=234
pool-1-thread-45, num=235
pool-1-thread-45, num=236
pool-1-thread-45, num=237
pool-1-thread-45, num=239
pool-1-thread-45, num=240
pool-1-thread-29, num=153
pool-1-thread-29, num=242
pool-1-thread-29, num=243
pool-1-thread-29, num=244
pool-1-thread-29, num=245
pool-1-thread-29, num=247
pool-1-thread-29, num=248
pool-1-thread-29, num=249
pool-1-thread-29, num=250
pool-1-thread-29, num=251
pool-1-thread-16, num=149
pool-1-thread-16, num=252
pool-1-thread-16, num=253
pool-1-thread-16, num=254
pool-1-thread-16, num=255
pool-1-thread-16, num=256
pool-1-thread-16, num=257
pool-1-thread-16, num=258
pool-1-thread-16, num=259
pool-1-thread-48, num=260
pool-1-thread-27, num=148
pool-1-thread-27, num=262
pool-1-thread-27, num=263
pool-1-thread-27, num=264
pool-1-thread-27, num=265
pool-1-thread-27, num=266
pool-1-thread-27, num=267
pool-1-thread-27, num=268
pool-1-thread-28, num=147
pool-1-thread-28, num=269
pool-1-thread-28, num=270
pool-1-thread-28, num=271
pool-1-thread-28, num=272
pool-1-thread-28, num=273
pool-1-thread-28, num=274
pool-1-thread-28, num=275
pool-1-thread-28, num=276
pool-1-thread-28, num=278
pool-1-thread-26, num=142
pool-1-thread-26, num=279
pool-1-thread-26, num=280
pool-1-thread-26, num=281
pool-1-thread-26, num=282
pool-1-thread-25, num=139
pool-1-thread-25, num=284
pool-1-thread-25, num=286
pool-1-thread-25, num=287
pool-1-thread-25, num=288
pool-1-thread-25, num=290
pool-1-thread-17, num=134
pool-1-thread-52, num=291
pool-1-thread-52, num=293
pool-1-thread-24, num=132
pool-1-thread-53, num=295
pool-1-thread-53, num=297
pool-1-thread-53, num=298
pool-1-thread-53, num=299
pool-1-thread-53, num=300
pool-1-thread-53, num=302
pool-1-thread-53, num=303
pool-1-thread-53, num=304
pool-1-thread-53, num=305
pool-1-thread-53, num=306
pool-1-thread-55, num=307
pool-1-thread-55, num=308
pool-1-thread-55, num=309
pool-1-thread-55, num=310
pool-1-thread-55, num=311
pool-1-thread-55, num=312
pool-1-thread-55, num=313
pool-1-thread-55, num=314
pool-1-thread-55, num=315
pool-1-thread-55, num=316
pool-1-thread-23, num=122
pool-1-thread-56, num=317
pool-1-thread-56, num=318
pool-1-thread-56, num=319
pool-1-thread-56, num=320
pool-1-thread-56, num=321
pool-1-thread-23, num=322
pool-1-thread-23, num=324
pool-1-thread-23, num=325
pool-1-thread-23, num=326
pool-1-thread-19, num=121
pool-1-thread-19, num=328
pool-1-thread-19, num=329
pool-1-thread-19, num=330
pool-1-thread-19, num=332
pool-1-thread-19, num=333
pool-1-thread-19, num=334
pool-1-thread-19, num=335
pool-1-thread-22, num=119
pool-1-thread-22, num=336
pool-1-thread-22, num=337
pool-1-thread-21, num=118
pool-1-thread-21, num=340
pool-1-thread-21, num=341
pool-1-thread-21, num=342
pool-1-thread-21, num=343
pool-1-thread-1, num=112
pool-1-thread-59, num=345
pool-1-thread-20, num=107
pool-1-thread-59, num=346
pool-1-thread-59, num=348
pool-1-thread-59, num=349
pool-1-thread-59, num=350
pool-1-thread-21, num=344
pool-1-thread-21, num=353
pool-1-thread-21, num=354
pool-1-thread-21, num=355
pool-1-thread-21, num=356
pool-1-thread-22, num=339
pool-1-thread-22, num=358
pool-1-thread-58, num=338
pool-1-thread-58, num=360
pool-1-thread-58, num=361
pool-1-thread-58, num=362
pool-1-thread-58, num=363
pool-1-thread-58, num=364
pool-1-thread-62, num=365
pool-1-thread-57, num=331
pool-1-thread-57, num=368
pool-1-thread-57, num=369
pool-1-thread-57, num=371
pool-1-thread-57, num=372
pool-1-thread-57, num=373
pool-1-thread-57, num=375
pool-1-thread-57, num=376
pool-1-thread-57, num=377
pool-1-thread-57, num=378
pool-1-thread-23, num=327
pool-1-thread-65, num=379
pool-1-thread-65, num=380
pool-1-thread-65, num=382
pool-1-thread-65, num=383
pool-1-thread-65, num=384
pool-1-thread-56, num=323
pool-1-thread-56, num=387
pool-1-thread-56, num=388
pool-1-thread-56, num=389
pool-1-thread-56, num=390
pool-1-thread-54, num=301
pool-1-thread-54, num=391
pool-1-thread-54, num=392
pool-1-thread-54, num=394
pool-1-thread-54, num=395
pool-1-thread-54, num=396
pool-1-thread-54, num=397
pool-1-thread-54, num=398
pool-1-thread-54, num=399
pool-1-thread-54, num=401
pool-1-thread-24, num=296
pool-1-thread-24, num=403
pool-1-thread-52, num=294
pool-1-thread-52, num=406
pool-1-thread-52, num=407
pool-1-thread-52, num=408
pool-1-thread-52, num=410
pool-1-thread-52, num=411
pool-1-thread-52, num=412
pool-1-thread-52, num=413
pool-1-thread-17, num=292
pool-1-thread-17, num=415
pool-1-thread-17, num=416
pool-1-thread-17, num=418
pool-1-thread-74, num=419
pool-1-thread-50, num=289
pool-1-thread-50, num=422
pool-1-thread-75, num=423
pool-1-thread-75, num=425
pool-1-thread-75, num=426
pool-1-thread-51, num=285
pool-1-thread-51, num=428
pool-1-thread-51, num=431
pool-1-thread-51, num=432
pool-1-thread-77, num=430
pool-1-thread-77, num=434
pool-1-thread-77, num=435
pool-1-thread-77, num=436
pool-1-thread-77, num=437
pool-1-thread-77, num=439
pool-1-thread-77, num=440
pool-1-thread-26, num=283
pool-1-thread-79, num=442
pool-1-thread-79, num=444
pool-1-thread-49, num=277
pool-1-thread-49, num=446
pool-1-thread-49, num=447
pool-1-thread-49, num=448
pool-1-thread-49, num=449
pool-1-thread-49, num=450
pool-1-thread-49, num=451
pool-1-thread-49, num=452
pool-1-thread-48, num=261
pool-1-thread-47, num=246
pool-1-thread-47, num=456
pool-1-thread-47, num=457
pool-1-thread-47, num=459
pool-1-thread-82, num=460
pool-1-thread-45, num=241
pool-1-thread-83, num=463
pool-1-thread-83, num=464
pool-1-thread-46, num=238
pool-1-thread-83, num=465
pool-1-thread-83, num=466
pool-1-thread-83, num=467
pool-1-thread-83, num=469
pool-1-thread-83, num=471
pool-1-thread-83, num=472
pool-1-thread-83, num=473
pool-1-thread-83, num=474
pool-1-thread-30, num=231
pool-1-thread-30, num=475
pool-1-thread-30, num=476
pool-1-thread-30, num=477
pool-1-thread-30, num=478
pool-1-thread-31, num=225
pool-1-thread-43, num=224
pool-1-thread-43, num=481
pool-1-thread-43, num=482
pool-1-thread-43, num=483
pool-1-thread-43, num=484
pool-1-thread-86, num=485
pool-1-thread-86, num=486
pool-1-thread-86, num=487
pool-1-thread-86, num=488
pool-1-thread-86, num=489
pool-1-thread-86, num=490
pool-1-thread-86, num=491
pool-1-thread-86, num=492
pool-1-thread-86, num=493
pool-1-thread-86, num=494
pool-1-thread-44, num=223
pool-1-thread-44, num=495
pool-1-thread-44, num=496
pool-1-thread-44, num=497
pool-1-thread-44, num=498
pool-1-thread-44, num=499
pool-1-thread-44, num=500
pool-1-thread-44, num=501
pool-1-thread-44, num=502
pool-1-thread-44, num=503
pool-1-thread-42, num=216
pool-1-thread-42, num=504
pool-1-thread-42, num=505
pool-1-thread-42, num=506
pool-1-thread-42, num=507
pool-1-thread-42, num=508
pool-1-thread-42, num=509
pool-1-thread-42, num=510
pool-1-thread-42, num=511
pool-1-thread-42, num=512
pool-1-thread-40, num=215
pool-1-thread-40, num=514
pool-1-thread-41, num=211
pool-1-thread-41, num=515
pool-1-thread-41, num=516
pool-1-thread-41, num=517
pool-1-thread-41, num=519
pool-1-thread-41, num=520
pool-1-thread-41, num=521
pool-1-thread-41, num=522
pool-1-thread-41, num=523
pool-1-thread-41, num=524
pool-1-thread-13, num=206
pool-1-thread-13, num=525
pool-1-thread-13, num=526
pool-1-thread-32, num=204
pool-1-thread-32, num=527
pool-1-thread-89, num=528
pool-1-thread-89, num=529
pool-1-thread-89, num=530
pool-1-thread-89, num=531
pool-1-thread-89, num=532
pool-1-thread-89, num=533
pool-1-thread-89, num=534
pool-1-thread-89, num=535
pool-1-thread-89, num=536
pool-1-thread-89, num=537
pool-1-thread-39, num=200
pool-1-thread-39, num=538
pool-1-thread-39, num=539
pool-1-thread-39, num=540
pool-1-thread-39, num=541
pool-1-thread-39, num=542
pool-1-thread-39, num=543
pool-1-thread-39, num=544
pool-1-thread-39, num=545
pool-1-thread-39, num=546
pool-1-thread-38, num=196
pool-1-thread-38, num=547
pool-1-thread-38, num=548
pool-1-thread-38, num=549
pool-1-thread-38, num=550
pool-1-thread-38, num=551
pool-1-thread-38, num=552
pool-1-thread-90, num=553
pool-1-thread-90, num=555
pool-1-thread-90, num=556
pool-1-thread-90, num=557
pool-1-thread-90, num=558
pool-1-thread-90, num=559
pool-1-thread-90, num=560
pool-1-thread-90, num=561
pool-1-thread-90, num=562
pool-1-thread-90, num=563
pool-1-thread-37, num=193
pool-1-thread-37, num=564
pool-1-thread-37, num=565
pool-1-thread-37, num=566
pool-1-thread-37, num=567
pool-1-thread-37, num=568
pool-1-thread-37, num=569
pool-1-thread-37, num=570
pool-1-thread-37, num=571
pool-1-thread-37, num=572
pool-1-thread-36, num=187
pool-1-thread-36, num=573
pool-1-thread-36, num=574
pool-1-thread-36, num=575
pool-1-thread-36, num=576
pool-1-thread-36, num=577
pool-1-thread-36, num=578
pool-1-thread-36, num=579
pool-1-thread-36, num=580
pool-1-thread-36, num=581
pool-1-thread-91, num=582
pool-1-thread-91, num=583
pool-1-thread-91, num=584
pool-1-thread-91, num=585
pool-1-thread-91, num=586
pool-1-thread-91, num=587
pool-1-thread-91, num=588
pool-1-thread-91, num=589
pool-1-thread-91, num=590
pool-1-thread-91, num=591
pool-1-thread-33, num=184
pool-1-thread-33, num=592
pool-1-thread-33, num=593
pool-1-thread-33, num=594
pool-1-thread-33, num=595
pool-1-thread-35, num=178
pool-1-thread-35, num=596
pool-1-thread-35, num=597
pool-1-thread-35, num=598
pool-1-thread-35, num=599
pool-1-thread-35, num=600
pool-1-thread-35, num=601
pool-1-thread-35, num=602
pool-1-thread-35, num=603
pool-1-thread-35, num=604
pool-1-thread-92, num=605
pool-1-thread-92, num=606
pool-1-thread-92, num=607
pool-1-thread-92, num=608
pool-1-thread-92, num=609
pool-1-thread-92, num=610
pool-1-thread-92, num=611
pool-1-thread-92, num=612
pool-1-thread-92, num=613
pool-1-thread-92, num=614
pool-1-thread-34, num=173
pool-1-thread-34, num=615
pool-1-thread-34, num=616
pool-1-thread-34, num=617
pool-1-thread-34, num=618
pool-1-thread-34, num=619
pool-1-thread-34, num=620
pool-1-thread-34, num=621
pool-1-thread-34, num=622
pool-1-thread-34, num=623
pool-1-thread-38, num=554
pool-1-thread-38, num=624
pool-1-thread-88, num=518
pool-1-thread-88, num=625
pool-1-thread-88, num=626
pool-1-thread-88, num=627
pool-1-thread-88, num=628
pool-1-thread-88, num=629
pool-1-thread-88, num=630
pool-1-thread-88, num=631
pool-1-thread-88, num=632
pool-1-thread-88, num=633
pool-1-thread-93, num=634
pool-1-thread-93, num=635
pool-1-thread-93, num=636
pool-1-thread-93, num=637
pool-1-thread-93, num=638
pool-1-thread-93, num=639
pool-1-thread-93, num=640
pool-1-thread-93, num=641
pool-1-thread-93, num=642
pool-1-thread-93, num=643
pool-1-thread-87, num=513
pool-1-thread-87, num=644
pool-1-thread-87, num=645
pool-1-thread-87, num=646
pool-1-thread-87, num=647
pool-1-thread-87, num=648
pool-1-thread-87, num=649
pool-1-thread-87, num=650
pool-1-thread-87, num=651
pool-1-thread-87, num=652
pool-1-thread-31, num=480
pool-1-thread-31, num=653
pool-1-thread-31, num=654
pool-1-thread-31, num=655
pool-1-thread-31, num=656
pool-1-thread-31, num=657
pool-1-thread-31, num=658
pool-1-thread-31, num=659
pool-1-thread-94, num=660
pool-1-thread-94, num=661
pool-1-thread-94, num=662
pool-1-thread-94, num=663
pool-1-thread-94, num=664
pool-1-thread-94, num=665
pool-1-thread-94, num=666
pool-1-thread-94, num=667
pool-1-thread-94, num=668
pool-1-thread-94, num=669
pool-1-thread-85, num=479
pool-1-thread-85, num=670
pool-1-thread-85, num=671
pool-1-thread-85, num=672
pool-1-thread-85, num=673
pool-1-thread-85, num=674
pool-1-thread-95, num=675
pool-1-thread-95, num=676
pool-1-thread-95, num=677
pool-1-thread-95, num=678
pool-1-thread-95, num=679
pool-1-thread-95, num=680
pool-1-thread-95, num=681
pool-1-thread-95, num=682
pool-1-thread-95, num=683
pool-1-thread-95, num=684
pool-1-thread-46, num=470
pool-1-thread-46, num=686
pool-1-thread-46, num=687
pool-1-thread-46, num=688
pool-1-thread-46, num=689
pool-1-thread-46, num=690
pool-1-thread-46, num=691
pool-1-thread-46, num=692
pool-1-thread-46, num=693
pool-1-thread-84, num=468
pool-1-thread-84, num=694
pool-1-thread-84, num=695
pool-1-thread-84, num=696
pool-1-thread-84, num=697
pool-1-thread-84, num=698
pool-1-thread-84, num=699
pool-1-thread-84, num=700
pool-1-thread-82, num=462
pool-1-thread-82, num=703
pool-1-thread-47, num=461
pool-1-thread-47, num=705
pool-1-thread-47, num=706
pool-1-thread-47, num=707
pool-1-thread-47, num=708
pool-1-thread-47, num=709
pool-1-thread-81, num=458
pool-1-thread-81, num=710
pool-1-thread-81, num=712
pool-1-thread-81, num=713
pool-1-thread-81, num=714
pool-1-thread-81, num=715
pool-1-thread-81, num=716
pool-1-thread-48, num=455
pool-1-thread-49, num=454
pool-1-thread-49, num=720
pool-1-thread-80, num=453
pool-1-thread-80, num=721
pool-1-thread-80, num=722
pool-1-thread-80, num=723
pool-1-thread-80, num=724
pool-1-thread-80, num=725
pool-1-thread-80, num=726
pool-1-thread-80, num=727
pool-1-thread-80, num=728
pool-1-thread-79, num=445
pool-1-thread-79, num=731
pool-1-thread-26, num=443
pool-1-thread-77, num=441
pool-1-thread-77, num=733
pool-1-thread-77, num=734
pool-1-thread-78, num=438
pool-1-thread-78, num=735
pool-1-thread-78, num=737
pool-1-thread-78, num=738
pool-1-thread-51, num=433
pool-1-thread-51, num=740
pool-1-thread-51, num=741
pool-1-thread-51, num=742
pool-1-thread-51, num=743
pool-1-thread-51, num=744
pool-1-thread-76, num=429
pool-1-thread-76, num=745
pool-1-thread-76, num=746
pool-1-thread-76, num=747
pool-1-thread-75, num=427
pool-1-thread-75, num=749
pool-1-thread-75, num=750
pool-1-thread-75, num=751
pool-1-thread-75, num=752
pool-1-thread-75, num=753
pool-1-thread-50, num=424
pool-1-thread-74, num=421
pool-1-thread-17, num=420
pool-1-thread-17, num=757
pool-1-thread-17, num=758
pool-1-thread-17, num=759
pool-1-thread-73, num=417
pool-1-thread-73, num=760
pool-1-thread-73, num=761
pool-1-thread-73, num=762
pool-1-thread-73, num=763
pool-1-thread-73, num=764
pool-1-thread-73, num=765
pool-1-thread-73, num=766
pool-1-thread-73, num=767
pool-1-thread-73, num=768
pool-1-thread-72, num=414
pool-1-thread-72, num=769
pool-1-thread-72, num=770
pool-1-thread-72, num=771
pool-1-thread-72, num=772
pool-1-thread-72, num=773
pool-1-thread-72, num=774
pool-1-thread-72, num=775
pool-1-thread-72, num=776
pool-1-thread-72, num=777
pool-1-thread-71, num=409
pool-1-thread-71, num=778
pool-1-thread-71, num=779
pool-1-thread-71, num=780
pool-1-thread-24, num=405
pool-1-thread-24, num=782
pool-1-thread-24, num=783
pool-1-thread-24, num=784
pool-1-thread-24, num=785
pool-1-thread-24, num=786
pool-1-thread-24, num=787
pool-1-thread-70, num=404
pool-1-thread-70, num=788
pool-1-thread-70, num=789
pool-1-thread-70, num=790
pool-1-thread-70, num=791
pool-1-thread-70, num=792
pool-1-thread-70, num=793
pool-1-thread-70, num=794
pool-1-thread-70, num=795
pool-1-thread-69, num=402
pool-1-thread-69, num=797
pool-1-thread-68, num=400
pool-1-thread-68, num=799
pool-1-thread-68, num=800
pool-1-thread-68, num=801
pool-1-thread-68, num=802
pool-1-thread-68, num=803
pool-1-thread-68, num=804
pool-1-thread-67, num=393
pool-1-thread-67, num=806
pool-1-thread-67, num=807
pool-1-thread-67, num=808
pool-1-thread-65, num=386
pool-1-thread-67, num=809
pool-1-thread-67, num=810
pool-1-thread-67, num=811
pool-1-thread-67, num=812
pool-1-thread-67, num=813
pool-1-thread-67, num=814
pool-1-thread-65, num=815
pool-1-thread-65, num=816
pool-1-thread-65, num=817
pool-1-thread-65, num=818
pool-1-thread-66, num=385
pool-1-thread-23, num=381
pool-1-thread-66, num=819
pool-1-thread-66, num=820
pool-1-thread-66, num=821
pool-1-thread-66, num=822
pool-1-thread-66, num=823
pool-1-thread-66, num=824
pool-1-thread-66, num=825
pool-1-thread-66, num=826
pool-1-thread-66, num=827
pool-1-thread-23, num=828
pool-1-thread-23, num=829
pool-1-thread-23, num=830
pool-1-thread-64, num=374
pool-1-thread-63, num=370
pool-1-thread-64, num=831
pool-1-thread-64, num=832
pool-1-thread-64, num=833
pool-1-thread-64, num=834
pool-1-thread-64, num=835
pool-1-thread-64, num=836
pool-1-thread-64, num=837
pool-1-thread-64, num=838
pool-1-thread-64, num=839
pool-1-thread-63, num=840
pool-1-thread-63, num=841
pool-1-thread-63, num=842
pool-1-thread-63, num=843
pool-1-thread-63, num=844
pool-1-thread-63, num=845
pool-1-thread-63, num=846
pool-1-thread-63, num=847
pool-1-thread-63, num=848
pool-1-thread-62, num=367
pool-1-thread-58, num=366
pool-1-thread-62, num=849
pool-1-thread-62, num=850
pool-1-thread-62, num=851
pool-1-thread-62, num=852
pool-1-thread-62, num=853
pool-1-thread-62, num=854
pool-1-thread-62, num=855
pool-1-thread-62, num=856
pool-1-thread-58, num=857
pool-1-thread-58, num=858
pool-1-thread-58, num=859
pool-1-thread-22, num=359
pool-1-thread-61, num=357
pool-1-thread-22, num=860
pool-1-thread-22, num=861
pool-1-thread-22, num=862
pool-1-thread-22, num=863
pool-1-thread-61, num=864
pool-1-thread-61, num=865
pool-1-thread-61, num=866
pool-1-thread-61, num=867
pool-1-thread-61, num=868
pool-1-thread-61, num=869
pool-1-thread-61, num=870
pool-1-thread-61, num=871
pool-1-thread-61, num=872
pool-1-thread-59, num=352
pool-1-thread-60, num=351
pool-1-thread-59, num=873
pool-1-thread-59, num=874
pool-1-thread-59, num=875
pool-1-thread-59, num=876
pool-1-thread-60, num=877
pool-1-thread-60, num=878
pool-1-thread-60, num=879
pool-1-thread-60, num=880
pool-1-thread-60, num=881
pool-1-thread-60, num=882
pool-1-thread-60, num=883
pool-1-thread-60, num=884
pool-1-thread-60, num=885
pool-1-thread-20, num=347
pool-1-thread-20, num=886
pool-1-thread-20, num=887
pool-1-thread-20, num=888
pool-1-thread-20, num=889
pool-1-thread-20, num=890
pool-1-thread-20, num=891
pool-1-thread-20, num=892
pool-1-thread-20, num=893
pool-1-thread-68, num=805
pool-1-thread-69, num=798
pool-1-thread-68, num=894
pool-1-thread-68, num=895
pool-1-thread-69, num=896
pool-1-thread-69, num=897
pool-1-thread-69, num=898
pool-1-thread-69, num=899
pool-1-thread-70, num=796
pool-1-thread-71, num=781
pool-1-thread-71, num=901
pool-1-thread-71, num=902
pool-1-thread-71, num=903
pool-1-thread-71, num=904
pool-1-thread-71, num=905
pool-1-thread-74, num=756
pool-1-thread-74, num=906
pool-1-thread-74, num=907
pool-1-thread-74, num=908
pool-1-thread-74, num=909
pool-1-thread-74, num=910
pool-1-thread-74, num=911
pool-1-thread-74, num=912
pool-1-thread-50, num=755
pool-1-thread-50, num=913
pool-1-thread-50, num=914
pool-1-thread-50, num=915
pool-1-thread-50, num=916
pool-1-thread-50, num=917
pool-1-thread-50, num=918
pool-1-thread-75, num=754
pool-1-thread-76, num=748
pool-1-thread-76, num=919
pool-1-thread-76, num=920
pool-1-thread-76, num=921
pool-1-thread-76, num=922
pool-1-thread-76, num=923
pool-1-thread-78, num=739
pool-1-thread-100, num=736
pool-1-thread-100, num=925
pool-1-thread-100, num=926
pool-1-thread-100, num=927
pool-1-thread-100, num=928
pool-1-thread-100, num=929
pool-1-thread-100, num=930
pool-1-thread-100, num=931
pool-1-thread-100, num=932
pool-1-thread-100, num=933
pool-1-thread-79, num=732
쓰레드 콜 종료
pool-1-thread-79, num=934
pool-1-thread-79, num=935
pool-1-thread-79, num=936
pool-1-thread-79, num=937
pool-1-thread-79, num=938
pool-1-thread-80, num=730
pool-1-thread-99, num=729
pool-1-thread-99, num=939
pool-1-thread-99, num=940
pool-1-thread-99, num=941
pool-1-thread-99, num=942
pool-1-thread-99, num=943
pool-1-thread-99, num=944
pool-1-thread-99, num=945
pool-1-thread-99, num=946
pool-1-thread-99, num=947
pool-1-thread-48, num=719
pool-1-thread-48, num=948
pool-1-thread-48, num=949
pool-1-thread-48, num=950
pool-1-thread-48, num=951
pool-1-thread-48, num=952
pool-1-thread-48, num=953
pool-1-thread-81, num=717
pool-1-thread-81, num=954
pool-1-thread-81, num=955
pool-1-thread-98, num=718
pool-1-thread-98, num=956
pool-1-thread-98, num=957
pool-1-thread-98, num=958
pool-1-thread-98, num=959
pool-1-thread-98, num=960
pool-1-thread-98, num=961
pool-1-thread-98, num=962
pool-1-thread-98, num=963
pool-1-thread-98, num=964
pool-1-thread-97, num=711
pool-1-thread-97, num=965
pool-1-thread-97, num=966
pool-1-thread-97, num=967
pool-1-thread-97, num=968
pool-1-thread-97, num=969
pool-1-thread-97, num=970
pool-1-thread-97, num=971
pool-1-thread-97, num=972
pool-1-thread-97, num=973
pool-1-thread-82, num=704
pool-1-thread-82, num=974
pool-1-thread-82, num=975
pool-1-thread-82, num=976
pool-1-thread-82, num=977
pool-1-thread-82, num=978
pool-1-thread-82, num=979
pool-1-thread-84, num=702
pool-1-thread-84, num=980
pool-1-thread-96, num=701
pool-1-thread-96, num=981
pool-1-thread-96, num=982
pool-1-thread-96, num=983
pool-1-thread-96, num=984
pool-1-thread-96, num=985
pool-1-thread-96, num=986
pool-1-thread-96, num=987
pool-1-thread-96, num=988
pool-1-thread-96, num=989
pool-1-thread-85, num=685
pool-1-thread-85, num=990
pool-1-thread-85, num=991
pool-1-thread-85, num=992
pool-1-thread-78, num=924
pool-1-thread-78, num=993
pool-1-thread-78, num=994
pool-1-thread-78, num=995
pool-1-thread-78, num=996
pool-1-thread-69, num=900
pool-1-thread-69, num=997
pool-1-thread-69, num=998
executor has been terminated

BUILD SUCCESSFUL in 0s
2 actionable tasks: 2 executed

 

위 출력 결과를 자세히 확인해보면 thread는 thread-1 ~ thread-100 까지 총 100개가 생성되어 실행이 된 것을 확인 할 수 있습니다. 

이번에는 corePoolSize를 1로 설정을 해서 실행해보겠습니다. (더보기 클릭해서 보세요)

더보기

pool-1-thread-2, num=0
pool-1-thread-3, num=0
pool-1-thread-1, num=1
pool-1-thread-3, num=3
pool-1-thread-3, num=5
pool-1-thread-2, num=2
pool-1-thread-2, num=7
pool-1-thread-3, num=6
pool-1-thread-1, num=4
pool-1-thread-3, num=9
pool-1-thread-2, num=8
pool-1-thread-3, num=11
pool-1-thread-1, num=10
pool-1-thread-3, num=13
pool-1-thread-2, num=12
pool-1-thread-3, num=15
pool-1-thread-1, num=14
pool-1-thread-1, num=18
pool-1-thread-3, num=17
pool-1-thread-2, num=16
pool-1-thread-3, num=20
pool-1-thread-1, num=19
pool-1-thread-2, num=21
pool-1-thread-3, num=23
pool-1-thread-1, num=22
pool-1-thread-1, num=26
pool-1-thread-3, num=25
pool-1-thread-2, num=24
pool-1-thread-2, num=29
pool-1-thread-2, num=30
pool-1-thread-3, num=28
pool-1-thread-1, num=27
pool-1-thread-3, num=31
pool-1-thread-3, num=33
pool-1-thread-3, num=34
pool-1-thread-3, num=35
pool-1-thread-3, num=36
pool-1-thread-1, num=32
pool-1-thread-3, num=37
pool-1-thread-3, num=38
pool-1-thread-4, num=39
pool-1-thread-4, num=40
pool-1-thread-4, num=41
pool-1-thread-4, num=42
pool-1-thread-4, num=43
pool-1-thread-4, num=44
pool-1-thread-4, num=45
pool-1-thread-4, num=46
pool-1-thread-4, num=47
pool-1-thread-4, num=48
pool-1-thread-4, num=49
pool-1-thread-4, num=50
pool-1-thread-2, num=51
pool-1-thread-4, num=52
pool-1-thread-4, num=54
pool-1-thread-2, num=53
pool-1-thread-4, num=55
pool-1-thread-4, num=57
pool-1-thread-4, num=58
pool-1-thread-2, num=56
pool-1-thread-4, num=59
pool-1-thread-2, num=60
pool-1-thread-4, num=61
pool-1-thread-2, num=62
pool-1-thread-2, num=64
pool-1-thread-4, num=63
pool-1-thread-2, num=65
pool-1-thread-2, num=66
pool-1-thread-2, num=67
pool-1-thread-2, num=68
pool-1-thread-5, num=69
pool-1-thread-5, num=70
pool-1-thread-5, num=71
pool-1-thread-5, num=72
pool-1-thread-5, num=73
pool-1-thread-5, num=74
pool-1-thread-5, num=75
pool-1-thread-5, num=76
pool-1-thread-5, num=77
pool-1-thread-5, num=78
pool-1-thread-5, num=79
pool-1-thread-5, num=80
pool-1-thread-5, num=81
pool-1-thread-5, num=82
pool-1-thread-5, num=83
pool-1-thread-3, num=84
pool-1-thread-5, num=85
pool-1-thread-3, num=86
pool-1-thread-5, num=87
pool-1-thread-3, num=88
pool-1-thread-3, num=90
pool-1-thread-5, num=89
pool-1-thread-3, num=91
pool-1-thread-5, num=92
pool-1-thread-3, num=93
pool-1-thread-5, num=94
pool-1-thread-3, num=95
pool-1-thread-3, num=96
pool-1-thread-3, num=97
pool-1-thread-3, num=98
pool-1-thread-6, num=99
pool-1-thread-6, num=100
pool-1-thread-6, num=101
pool-1-thread-6, num=102
pool-1-thread-6, num=103
pool-1-thread-6, num=104
pool-1-thread-6, num=105
pool-1-thread-6, num=106
pool-1-thread-6, num=107
pool-1-thread-6, num=108
pool-1-thread-4, num=109
pool-1-thread-4, num=110
pool-1-thread-4, num=111
pool-1-thread-4, num=112
pool-1-thread-4, num=113
pool-1-thread-4, num=114
pool-1-thread-4, num=115
pool-1-thread-4, num=116
pool-1-thread-4, num=117
pool-1-thread-4, num=118
pool-1-thread-2, num=119
pool-1-thread-2, num=120
pool-1-thread-2, num=121
pool-1-thread-2, num=122
pool-1-thread-2, num=123
pool-1-thread-2, num=124
pool-1-thread-2, num=125
pool-1-thread-2, num=126
pool-1-thread-2, num=127
pool-1-thread-2, num=128
pool-1-thread-1, num=129
pool-1-thread-1, num=130
pool-1-thread-1, num=131
pool-1-thread-1, num=132
pool-1-thread-1, num=133
pool-1-thread-1, num=134
pool-1-thread-1, num=135
pool-1-thread-1, num=136
pool-1-thread-1, num=137
pool-1-thread-1, num=138
pool-1-thread-7, num=139
pool-1-thread-7, num=140
pool-1-thread-7, num=141
pool-1-thread-7, num=142
pool-1-thread-7, num=143
pool-1-thread-7, num=144
pool-1-thread-7, num=145
pool-1-thread-7, num=146
pool-1-thread-7, num=147
pool-1-thread-7, num=148
pool-1-thread-5, num=149
pool-1-thread-5, num=150
pool-1-thread-5, num=151
pool-1-thread-5, num=152
pool-1-thread-5, num=153
pool-1-thread-5, num=154
pool-1-thread-5, num=155
pool-1-thread-5, num=156
pool-1-thread-5, num=157
pool-1-thread-5, num=158
pool-1-thread-3, num=159
pool-1-thread-3, num=160
pool-1-thread-3, num=161
pool-1-thread-3, num=162
pool-1-thread-3, num=163
pool-1-thread-3, num=164
pool-1-thread-3, num=165
pool-1-thread-3, num=166
pool-1-thread-3, num=167
pool-1-thread-3, num=168
pool-1-thread-8, num=169
pool-1-thread-8, num=170
pool-1-thread-8, num=171
pool-1-thread-8, num=172
pool-1-thread-8, num=173
pool-1-thread-8, num=174
pool-1-thread-8, num=175
pool-1-thread-8, num=176
pool-1-thread-8, num=177
pool-1-thread-8, num=178
pool-1-thread-6, num=179
pool-1-thread-6, num=180
pool-1-thread-6, num=181
pool-1-thread-6, num=182
pool-1-thread-6, num=183
pool-1-thread-6, num=184
pool-1-thread-6, num=185
pool-1-thread-6, num=186
pool-1-thread-6, num=187
pool-1-thread-6, num=188
pool-1-thread-4, num=189
pool-1-thread-9, num=190
pool-1-thread-9, num=192
pool-1-thread-9, num=193
pool-1-thread-9, num=194
pool-1-thread-4, num=191
pool-1-thread-9, num=195
pool-1-thread-4, num=196
pool-1-thread-9, num=197
pool-1-thread-4, num=198
pool-1-thread-4, num=200
pool-1-thread-9, num=199
pool-1-thread-9, num=202
pool-1-thread-4, num=201
pool-1-thread-9, num=203
pool-1-thread-9, num=205
pool-1-thread-4, num=204
pool-1-thread-4, num=206
pool-1-thread-4, num=207
pool-1-thread-4, num=208
pool-1-thread-2, num=209
pool-1-thread-2, num=210
pool-1-thread-10, num=211
pool-1-thread-10, num=213
pool-1-thread-10, num=214
pool-1-thread-10, num=215
pool-1-thread-10, num=216
pool-1-thread-2, num=212
pool-1-thread-10, num=217
pool-1-thread-2, num=218
pool-1-thread-2, num=220
pool-1-thread-10, num=219
pool-1-thread-2, num=221
pool-1-thread-10, num=222
pool-1-thread-10, num=224
pool-1-thread-2, num=223
pool-1-thread-2, num=226
pool-1-thread-10, num=225
pool-1-thread-2, num=227
pool-1-thread-2, num=228
pool-1-thread-11, num=229
pool-1-thread-11, num=230
pool-1-thread-11, num=231
pool-1-thread-11, num=232
pool-1-thread-11, num=233
pool-1-thread-11, num=234
pool-1-thread-11, num=235
pool-1-thread-1, num=236
pool-1-thread-11, num=237
pool-1-thread-1, num=238
pool-1-thread-11, num=239
pool-1-thread-1, num=240
pool-1-thread-1, num=241
pool-1-thread-1, num=242
pool-1-thread-1, num=243
pool-1-thread-1, num=244
pool-1-thread-1, num=245
pool-1-thread-1, num=246
pool-1-thread-1, num=247
pool-1-thread-11, num=248
pool-1-thread-7, num=249
pool-1-thread-7, num=250
pool-1-thread-7, num=251
pool-1-thread-12, num=252
pool-1-thread-7, num=253
pool-1-thread-12, num=254
pool-1-thread-12, num=257
pool-1-thread-12, num=258
pool-1-thread-12, num=259
pool-1-thread-12, num=260
pool-1-thread-5, num=256
pool-1-thread-7, num=255
pool-1-thread-5, num=262
pool-1-thread-5, num=264
pool-1-thread-5, num=265
pool-1-thread-12, num=261
pool-1-thread-5, num=266
pool-1-thread-5, num=268
pool-1-thread-5, num=269
pool-1-thread-5, num=270
pool-1-thread-5, num=271
pool-1-thread-5, num=272
pool-1-thread-7, num=263
pool-1-thread-7, num=273
pool-1-thread-12, num=267
pool-1-thread-12, num=275
pool-1-thread-12, num=276
pool-1-thread-7, num=274
pool-1-thread-7, num=277
pool-1-thread-7, num=278
pool-1-thread-3, num=279
pool-1-thread-3, num=280
pool-1-thread-3, num=281
pool-1-thread-3, num=282
pool-1-thread-3, num=283
pool-1-thread-3, num=284
pool-1-thread-3, num=285
pool-1-thread-3, num=286
pool-1-thread-3, num=287
pool-1-thread-3, num=288
pool-1-thread-8, num=289
pool-1-thread-8, num=290
pool-1-thread-8, num=291
pool-1-thread-8, num=292
pool-1-thread-8, num=293
pool-1-thread-8, num=294
pool-1-thread-8, num=295
pool-1-thread-8, num=296
pool-1-thread-8, num=297
pool-1-thread-8, num=298
pool-1-thread-6, num=299
pool-1-thread-6, num=300
pool-1-thread-6, num=301
pool-1-thread-6, num=302
pool-1-thread-6, num=303
pool-1-thread-6, num=304
pool-1-thread-6, num=305
pool-1-thread-6, num=306
pool-1-thread-6, num=307
pool-1-thread-6, num=308
pool-1-thread-13, num=309
pool-1-thread-13, num=310
pool-1-thread-13, num=311
pool-1-thread-13, num=312
pool-1-thread-13, num=313
pool-1-thread-13, num=314
pool-1-thread-13, num=315
pool-1-thread-13, num=316
pool-1-thread-13, num=317
pool-1-thread-13, num=318
pool-1-thread-9, num=319
pool-1-thread-9, num=320
pool-1-thread-9, num=321
pool-1-thread-9, num=322
pool-1-thread-9, num=323
pool-1-thread-9, num=324
pool-1-thread-9, num=325
pool-1-thread-9, num=326
pool-1-thread-9, num=327
pool-1-thread-9, num=328
pool-1-thread-14, num=329
pool-1-thread-14, num=330
pool-1-thread-14, num=331
pool-1-thread-14, num=332
pool-1-thread-14, num=333
pool-1-thread-14, num=334
pool-1-thread-14, num=335
pool-1-thread-14, num=336
pool-1-thread-14, num=337
pool-1-thread-14, num=338
pool-1-thread-4, num=339
pool-1-thread-4, num=340
pool-1-thread-4, num=341
pool-1-thread-4, num=342
pool-1-thread-4, num=343
pool-1-thread-4, num=344
pool-1-thread-4, num=345
pool-1-thread-4, num=346
pool-1-thread-4, num=347
pool-1-thread-4, num=348
pool-1-thread-10, num=349
pool-1-thread-10, num=350
pool-1-thread-10, num=351
pool-1-thread-10, num=352
pool-1-thread-10, num=353
pool-1-thread-10, num=354
pool-1-thread-10, num=355
pool-1-thread-10, num=356
pool-1-thread-10, num=357
pool-1-thread-10, num=358
pool-1-thread-2, num=359
pool-1-thread-2, num=360
pool-1-thread-2, num=361
pool-1-thread-2, num=362
pool-1-thread-2, num=363
pool-1-thread-2, num=364
pool-1-thread-2, num=365
pool-1-thread-2, num=366
pool-1-thread-2, num=367
pool-1-thread-2, num=368
pool-1-thread-1, num=369
pool-1-thread-1, num=370
pool-1-thread-1, num=371
pool-1-thread-1, num=372
pool-1-thread-1, num=373
pool-1-thread-1, num=374
pool-1-thread-1, num=375
pool-1-thread-1, num=376
pool-1-thread-1, num=377
pool-1-thread-1, num=378
pool-1-thread-15, num=379
pool-1-thread-15, num=380
pool-1-thread-15, num=381
pool-1-thread-15, num=382
pool-1-thread-15, num=383
pool-1-thread-15, num=384
pool-1-thread-15, num=385
pool-1-thread-15, num=386
pool-1-thread-15, num=387
pool-1-thread-15, num=388
pool-1-thread-11, num=389
pool-1-thread-11, num=390
pool-1-thread-11, num=391
pool-1-thread-11, num=392
pool-1-thread-11, num=393
pool-1-thread-11, num=394
pool-1-thread-11, num=395
pool-1-thread-11, num=396
pool-1-thread-11, num=397
pool-1-thread-11, num=398
pool-1-thread-5, num=399
pool-1-thread-5, num=400
pool-1-thread-5, num=401
pool-1-thread-5, num=402
pool-1-thread-5, num=403
pool-1-thread-5, num=404
pool-1-thread-5, num=405
pool-1-thread-5, num=406
pool-1-thread-5, num=407
pool-1-thread-5, num=408
pool-1-thread-12, num=409
pool-1-thread-12, num=410
pool-1-thread-12, num=411
pool-1-thread-12, num=412
pool-1-thread-12, num=413
pool-1-thread-12, num=414
pool-1-thread-12, num=415
pool-1-thread-12, num=416
pool-1-thread-12, num=417
pool-1-thread-12, num=418
pool-1-thread-7, num=419
pool-1-thread-7, num=420
pool-1-thread-7, num=421
pool-1-thread-7, num=422
pool-1-thread-7, num=423
pool-1-thread-7, num=424
pool-1-thread-7, num=425
pool-1-thread-7, num=426
pool-1-thread-7, num=427
pool-1-thread-7, num=428
pool-1-thread-16, num=429
pool-1-thread-16, num=430
pool-1-thread-16, num=431
pool-1-thread-16, num=432
pool-1-thread-16, num=433
pool-1-thread-16, num=434
pool-1-thread-16, num=435
pool-1-thread-16, num=436
pool-1-thread-16, num=437
pool-1-thread-16, num=438
pool-1-thread-3, num=439
pool-1-thread-3, num=440
pool-1-thread-3, num=441
pool-1-thread-3, num=442
pool-1-thread-3, num=443
pool-1-thread-3, num=444
pool-1-thread-3, num=445
pool-1-thread-3, num=446
pool-1-thread-3, num=447
pool-1-thread-3, num=448
pool-1-thread-8, num=449
pool-1-thread-8, num=450
pool-1-thread-8, num=451
pool-1-thread-8, num=452
pool-1-thread-8, num=453
pool-1-thread-8, num=454
pool-1-thread-8, num=455
pool-1-thread-8, num=456
pool-1-thread-8, num=457
pool-1-thread-8, num=458
pool-1-thread-6, num=459
pool-1-thread-6, num=460
pool-1-thread-6, num=461
pool-1-thread-6, num=462
pool-1-thread-6, num=463
pool-1-thread-6, num=464
pool-1-thread-6, num=465
pool-1-thread-6, num=466
pool-1-thread-6, num=467
pool-1-thread-6, num=468
pool-1-thread-6, num=469
pool-1-thread-6, num=470
pool-1-thread-6, num=471
pool-1-thread-6, num=472
pool-1-thread-6, num=473
pool-1-thread-6, num=474
pool-1-thread-6, num=475
pool-1-thread-6, num=476
pool-1-thread-6, num=477
pool-1-thread-6, num=478
pool-1-thread-9, num=479
pool-1-thread-9, num=480
pool-1-thread-9, num=481
pool-1-thread-9, num=482
pool-1-thread-9, num=483
pool-1-thread-9, num=484
pool-1-thread-9, num=485
pool-1-thread-9, num=486
pool-1-thread-9, num=487
pool-1-thread-9, num=488
pool-1-thread-17, num=489
pool-1-thread-17, num=490
pool-1-thread-17, num=491
pool-1-thread-17, num=492
pool-1-thread-17, num=493
pool-1-thread-17, num=494
pool-1-thread-17, num=495
pool-1-thread-17, num=496
pool-1-thread-17, num=497
pool-1-thread-17, num=498
pool-1-thread-14, num=499
pool-1-thread-14, num=500
pool-1-thread-14, num=501
pool-1-thread-14, num=502
pool-1-thread-14, num=503
pool-1-thread-14, num=504
pool-1-thread-14, num=505
pool-1-thread-14, num=506
pool-1-thread-14, num=507
pool-1-thread-14, num=508
pool-1-thread-4, num=509
pool-1-thread-4, num=510
pool-1-thread-4, num=511
pool-1-thread-4, num=512
pool-1-thread-4, num=513
pool-1-thread-4, num=514
pool-1-thread-4, num=515
pool-1-thread-4, num=516
pool-1-thread-4, num=517
pool-1-thread-4, num=518
pool-1-thread-10, num=519
pool-1-thread-10, num=520
pool-1-thread-10, num=521
pool-1-thread-10, num=522
pool-1-thread-10, num=523
pool-1-thread-10, num=524
pool-1-thread-10, num=525
pool-1-thread-10, num=526
pool-1-thread-10, num=527
pool-1-thread-10, num=528
pool-1-thread-2, num=529
pool-1-thread-2, num=530
pool-1-thread-2, num=531
pool-1-thread-2, num=532
pool-1-thread-2, num=533
pool-1-thread-2, num=534
pool-1-thread-2, num=535
pool-1-thread-2, num=536
pool-1-thread-2, num=537
pool-1-thread-2, num=538
pool-1-thread-1, num=539
pool-1-thread-1, num=540
pool-1-thread-1, num=541
pool-1-thread-1, num=542
pool-1-thread-1, num=543
pool-1-thread-1, num=544
pool-1-thread-1, num=545
pool-1-thread-1, num=546
pool-1-thread-1, num=547
pool-1-thread-1, num=548
pool-1-thread-15, num=549
pool-1-thread-15, num=550
pool-1-thread-15, num=551
pool-1-thread-15, num=552
pool-1-thread-15, num=553
pool-1-thread-15, num=554
pool-1-thread-15, num=555
pool-1-thread-15, num=556
pool-1-thread-15, num=557
pool-1-thread-15, num=558
pool-1-thread-18, num=559
pool-1-thread-18, num=560
pool-1-thread-18, num=561
pool-1-thread-18, num=562
pool-1-thread-18, num=563
pool-1-thread-18, num=564
pool-1-thread-18, num=565
pool-1-thread-18, num=566
pool-1-thread-18, num=567
pool-1-thread-18, num=568
pool-1-thread-11, num=569
pool-1-thread-11, num=570
pool-1-thread-11, num=571
pool-1-thread-11, num=572
pool-1-thread-11, num=573
pool-1-thread-11, num=574
pool-1-thread-11, num=575
pool-1-thread-11, num=576
pool-1-thread-11, num=577
pool-1-thread-11, num=578
pool-1-thread-5, num=579
pool-1-thread-5, num=580
pool-1-thread-5, num=581
pool-1-thread-5, num=582
pool-1-thread-5, num=583
pool-1-thread-5, num=584
pool-1-thread-5, num=585
pool-1-thread-5, num=586
pool-1-thread-5, num=587
pool-1-thread-5, num=588
pool-1-thread-12, num=589
pool-1-thread-12, num=590
pool-1-thread-12, num=591
pool-1-thread-12, num=592
pool-1-thread-12, num=593
pool-1-thread-12, num=594
pool-1-thread-12, num=595
pool-1-thread-12, num=596
pool-1-thread-12, num=597
pool-1-thread-12, num=598
pool-1-thread-7, num=599
pool-1-thread-7, num=600
pool-1-thread-7, num=601
pool-1-thread-7, num=602
pool-1-thread-7, num=603
pool-1-thread-7, num=604
pool-1-thread-7, num=605
pool-1-thread-7, num=606
pool-1-thread-7, num=607
pool-1-thread-7, num=608
pool-1-thread-19, num=609
pool-1-thread-19, num=610
pool-1-thread-19, num=611
pool-1-thread-19, num=612
pool-1-thread-19, num=613
pool-1-thread-19, num=614
pool-1-thread-19, num=615
pool-1-thread-19, num=616
pool-1-thread-19, num=617
pool-1-thread-19, num=618
pool-1-thread-16, num=619
pool-1-thread-16, num=620
pool-1-thread-16, num=621
pool-1-thread-16, num=622
pool-1-thread-16, num=623
pool-1-thread-16, num=624
pool-1-thread-16, num=625
pool-1-thread-16, num=626
pool-1-thread-16, num=627
pool-1-thread-16, num=628
pool-1-thread-3, num=629
pool-1-thread-3, num=630
pool-1-thread-3, num=631
pool-1-thread-3, num=632
pool-1-thread-3, num=633
pool-1-thread-3, num=634
pool-1-thread-3, num=635
pool-1-thread-3, num=636
pool-1-thread-3, num=637
pool-1-thread-3, num=638
pool-1-thread-8, num=639
pool-1-thread-8, num=640
pool-1-thread-8, num=641
pool-1-thread-8, num=642
pool-1-thread-8, num=643
pool-1-thread-8, num=644
pool-1-thread-8, num=645
pool-1-thread-8, num=646
pool-1-thread-8, num=647
pool-1-thread-8, num=648
pool-1-thread-6, num=649
pool-1-thread-6, num=650
pool-1-thread-6, num=651
pool-1-thread-6, num=652
pool-1-thread-6, num=653
pool-1-thread-6, num=654
pool-1-thread-6, num=655
pool-1-thread-6, num=656
pool-1-thread-6, num=657
pool-1-thread-6, num=658
pool-1-thread-13, num=659
pool-1-thread-13, num=660
pool-1-thread-13, num=661
pool-1-thread-13, num=662
pool-1-thread-13, num=663
pool-1-thread-13, num=664
pool-1-thread-13, num=665
pool-1-thread-13, num=666
pool-1-thread-13, num=667
pool-1-thread-13, num=668
pool-1-thread-9, num=669
pool-1-thread-9, num=670
pool-1-thread-9, num=671
pool-1-thread-9, num=672
pool-1-thread-9, num=673
pool-1-thread-9, num=674
pool-1-thread-9, num=675
pool-1-thread-9, num=676
pool-1-thread-9, num=677
pool-1-thread-9, num=678
pool-1-thread-20, num=679
pool-1-thread-20, num=680
pool-1-thread-20, num=681
pool-1-thread-20, num=682
pool-1-thread-20, num=683
pool-1-thread-20, num=684
pool-1-thread-20, num=685
pool-1-thread-20, num=686
pool-1-thread-20, num=687
pool-1-thread-20, num=688
pool-1-thread-17, num=689
pool-1-thread-17, num=690
pool-1-thread-17, num=691
pool-1-thread-17, num=692
pool-1-thread-17, num=693
pool-1-thread-17, num=694
pool-1-thread-17, num=695
pool-1-thread-17, num=696
pool-1-thread-17, num=697
pool-1-thread-17, num=698
pool-1-thread-14, num=699
pool-1-thread-14, num=700
pool-1-thread-14, num=701
pool-1-thread-14, num=702
pool-1-thread-14, num=703
pool-1-thread-14, num=704
pool-1-thread-14, num=705
pool-1-thread-14, num=706
pool-1-thread-14, num=707
pool-1-thread-14, num=708
pool-1-thread-4, num=709
pool-1-thread-4, num=710
pool-1-thread-4, num=711
pool-1-thread-4, num=712
pool-1-thread-4, num=713
pool-1-thread-4, num=714
pool-1-thread-4, num=715
pool-1-thread-4, num=716
pool-1-thread-4, num=717
pool-1-thread-4, num=718
pool-1-thread-10, num=719
pool-1-thread-10, num=720
pool-1-thread-10, num=721
pool-1-thread-10, num=722
pool-1-thread-10, num=723
pool-1-thread-10, num=724
pool-1-thread-10, num=725
pool-1-thread-10, num=726
pool-1-thread-10, num=727
pool-1-thread-10, num=728
pool-1-thread-2, num=729
pool-1-thread-2, num=730
pool-1-thread-2, num=731
pool-1-thread-2, num=732
pool-1-thread-2, num=733
pool-1-thread-2, num=734
pool-1-thread-2, num=735
pool-1-thread-2, num=736
pool-1-thread-2, num=737
pool-1-thread-2, num=738
pool-1-thread-1, num=739
pool-1-thread-1, num=740
pool-1-thread-1, num=741
pool-1-thread-1, num=742
pool-1-thread-1, num=743
pool-1-thread-1, num=744
pool-1-thread-1, num=745
pool-1-thread-1, num=746
pool-1-thread-1, num=747
pool-1-thread-1, num=748
pool-1-thread-21, num=749
pool-1-thread-21, num=750
pool-1-thread-21, num=751
pool-1-thread-21, num=752
pool-1-thread-21, num=753
pool-1-thread-21, num=754
pool-1-thread-21, num=755
pool-1-thread-21, num=756
pool-1-thread-21, num=757
pool-1-thread-21, num=758
pool-1-thread-15, num=759
pool-1-thread-15, num=760
pool-1-thread-15, num=761
pool-1-thread-15, num=762
pool-1-thread-15, num=763
pool-1-thread-15, num=764
pool-1-thread-15, num=765
pool-1-thread-15, num=766
pool-1-thread-15, num=767
pool-1-thread-15, num=768
pool-1-thread-18, num=769
pool-1-thread-18, num=770
pool-1-thread-18, num=771
pool-1-thread-18, num=772
pool-1-thread-18, num=773
pool-1-thread-18, num=774
pool-1-thread-18, num=775
pool-1-thread-18, num=776
pool-1-thread-18, num=777
pool-1-thread-18, num=778
pool-1-thread-11, num=779
pool-1-thread-11, num=780
pool-1-thread-11, num=781
pool-1-thread-11, num=782
pool-1-thread-11, num=783
pool-1-thread-11, num=784
pool-1-thread-11, num=785
pool-1-thread-11, num=786
pool-1-thread-11, num=787
pool-1-thread-11, num=788
pool-1-thread-22, num=789
pool-1-thread-22, num=790
pool-1-thread-22, num=791
pool-1-thread-22, num=792
pool-1-thread-22, num=793
pool-1-thread-22, num=794
pool-1-thread-22, num=795
pool-1-thread-22, num=796
pool-1-thread-22, num=797
pool-1-thread-22, num=798
pool-1-thread-5, num=799
pool-1-thread-5, num=800
pool-1-thread-5, num=801
pool-1-thread-5, num=802
pool-1-thread-5, num=803
pool-1-thread-5, num=804
pool-1-thread-5, num=805
pool-1-thread-5, num=806
pool-1-thread-5, num=807
pool-1-thread-5, num=808
pool-1-thread-23, num=809
pool-1-thread-23, num=810
pool-1-thread-23, num=811
pool-1-thread-23, num=812
pool-1-thread-23, num=813
pool-1-thread-23, num=814
pool-1-thread-23, num=815
pool-1-thread-23, num=816
pool-1-thread-23, num=817
pool-1-thread-23, num=818
pool-1-thread-12, num=819
pool-1-thread-12, num=820
pool-1-thread-12, num=821
pool-1-thread-12, num=822
pool-1-thread-12, num=823
pool-1-thread-12, num=824
pool-1-thread-12, num=825
pool-1-thread-12, num=826
pool-1-thread-12, num=827
pool-1-thread-12, num=828
pool-1-thread-7, num=829
pool-1-thread-7, num=830
pool-1-thread-7, num=831
pool-1-thread-7, num=832
pool-1-thread-7, num=833
pool-1-thread-7, num=834
pool-1-thread-7, num=835
pool-1-thread-7, num=836
pool-1-thread-7, num=837
pool-1-thread-7, num=838
pool-1-thread-24, num=839
pool-1-thread-24, num=840
pool-1-thread-24, num=841
pool-1-thread-24, num=842
pool-1-thread-24, num=843
pool-1-thread-24, num=844
pool-1-thread-24, num=845
pool-1-thread-24, num=846
pool-1-thread-24, num=847
pool-1-thread-24, num=848
pool-1-thread-24, num=849
pool-1-thread-24, num=850
pool-1-thread-24, num=851
pool-1-thread-24, num=852
pool-1-thread-24, num=853
pool-1-thread-24, num=854
pool-1-thread-24, num=855
pool-1-thread-24, num=856
pool-1-thread-24, num=857
pool-1-thread-24, num=858
pool-1-thread-19, num=859
pool-1-thread-19, num=860
pool-1-thread-19, num=861
pool-1-thread-19, num=862
pool-1-thread-19, num=863
pool-1-thread-19, num=864
pool-1-thread-19, num=865
pool-1-thread-19, num=866
pool-1-thread-19, num=867
pool-1-thread-19, num=868
pool-1-thread-3, num=869
pool-1-thread-3, num=870
pool-1-thread-3, num=871
pool-1-thread-3, num=872
pool-1-thread-3, num=873
pool-1-thread-3, num=874
pool-1-thread-3, num=875
pool-1-thread-3, num=876
pool-1-thread-3, num=877
pool-1-thread-3, num=878
pool-1-thread-25, num=879
pool-1-thread-25, num=880
pool-1-thread-25, num=881
pool-1-thread-25, num=882
pool-1-thread-25, num=883
pool-1-thread-25, num=884
pool-1-thread-25, num=885
pool-1-thread-25, num=886
pool-1-thread-25, num=887
pool-1-thread-25, num=888
pool-1-thread-8, num=889
pool-1-thread-8, num=890
pool-1-thread-8, num=891
pool-1-thread-8, num=892
pool-1-thread-8, num=893
pool-1-thread-8, num=894
pool-1-thread-8, num=895
pool-1-thread-8, num=896
pool-1-thread-8, num=897
pool-1-thread-8, num=898
pool-1-thread-6, num=899
pool-1-thread-6, num=900
pool-1-thread-6, num=901
pool-1-thread-6, num=902
pool-1-thread-6, num=903
pool-1-thread-6, num=904
pool-1-thread-6, num=905
pool-1-thread-6, num=906
pool-1-thread-6, num=907
pool-1-thread-6, num=908
pool-1-thread-13, num=909
pool-1-thread-13, num=910
pool-1-thread-13, num=911
pool-1-thread-26, num=912
pool-1-thread-26, num=914
pool-1-thread-26, num=915
pool-1-thread-26, num=916
pool-1-thread-26, num=917
pool-1-thread-26, num=918
pool-1-thread-26, num=919
pool-1-thread-26, num=920
pool-1-thread-26, num=921
pool-1-thread-26, num=922
pool-1-thread-13, num=913
pool-1-thread-13, num=923
pool-1-thread-13, num=924
pool-1-thread-13, num=925
pool-1-thread-13, num=926
pool-1-thread-13, num=927
pool-1-thread-13, num=928
pool-1-thread-9, num=929
pool-1-thread-9, num=930
pool-1-thread-9, num=931
pool-1-thread-9, num=932
pool-1-thread-9, num=933
pool-1-thread-9, num=934
pool-1-thread-9, num=935
pool-1-thread-9, num=936
pool-1-thread-9, num=937
pool-1-thread-9, num=938
pool-1-thread-20, num=939
pool-1-thread-20, num=940
pool-1-thread-20, num=941
pool-1-thread-20, num=942
pool-1-thread-20, num=943
pool-1-thread-20, num=944
pool-1-thread-20, num=945
pool-1-thread-20, num=946
pool-1-thread-20, num=947
pool-1-thread-20, num=948
pool-1-thread-17, num=949
pool-1-thread-17, num=950
pool-1-thread-17, num=951
pool-1-thread-17, num=952
pool-1-thread-17, num=953
pool-1-thread-17, num=954
pool-1-thread-17, num=955
pool-1-thread-17, num=956
pool-1-thread-17, num=957
pool-1-thread-17, num=958
pool-1-thread-27, num=959
pool-1-thread-27, num=960
pool-1-thread-27, num=961
pool-1-thread-27, num=962
pool-1-thread-27, num=963
pool-1-thread-27, num=964
pool-1-thread-27, num=965
pool-1-thread-27, num=966
pool-1-thread-27, num=967
pool-1-thread-27, num=968
pool-1-thread-14, num=969
pool-1-thread-14, num=970
pool-1-thread-14, num=971
pool-1-thread-14, num=972
pool-1-thread-14, num=973
pool-1-thread-14, num=974
pool-1-thread-14, num=975
pool-1-thread-14, num=976
pool-1-thread-14, num=977
pool-1-thread-14, num=978
pool-1-thread-4, num=979
pool-1-thread-4, num=980
pool-1-thread-4, num=981
pool-1-thread-4, num=982
pool-1-thread-4, num=983
pool-1-thread-4, num=984
pool-1-thread-4, num=985
pool-1-thread-4, num=986
pool-1-thread-4, num=987
pool-1-thread-4, num=988
pool-1-thread-10, num=989
pool-1-thread-10, num=990
pool-1-thread-10, num=991
pool-1-thread-10, num=992
pool-1-thread-10, num=993
pool-1-thread-10, num=994
pool-1-thread-10, num=995
pool-1-thread-10, num=996
pool-1-thread-10, num=997
pool-1-thread-10, num=998
쓰레드 콜 종료
executor has been terminated

BUILD SUCCESSFUL in 0s
2 actionable tasks: 2 executed

 

thread가 1~27 까지 27개의 쓰레드만 실행이 되었습니다. 왜 이런 걸까요?

corePoolSize를 1로 주었기 때문에 쓰레드풀은 1개의 쓰레드로 시작을 하게되고 해당 쓰레드가 끝나기 전에 새로운 task의 실행 요청이 들어오면 새로운 쓰레드를 생성해서 처리하게 됩니다. 하지만 새로운 task의 실행 요청이 이전 task가 종료된 이후에 들어오게되면 새로운 쓰레드를 생성하지 않고 기존의 쓰레드를 재사용하게 됩니다. 이것이 바로 쓰레드 풀을 사용하는 장점이죠. 쓰레드 풀에 필요한 개수만큼의 쓰레드만 생성하고 재사용함으로써 불필요한 쓰레드를 만듬으로써 소모되는 메모리를 줄일 수 있습니다.

 

여기까지 ThreadPoolExecutor를 활용한 멀티쓰레드 구현에 대해 간략한 포스팅을 마칩니다.

 

Reference: 오라클 Java 8 공식 문서

 

추가로 현재 Thread 클래스를 상속한 Task에서 num 변수를 1씩 증가해서 출력하도록 하였습니다만, 실제로 마지막 숫자를 보면 999가 아닌 998이 출력되었습니다. 여러 번 실행해보면 가장 큰 숫자가 99X~999가 랜덤하게 출력되는 것을 확인 할 수 있습니다. 이것은 num이라는 변수를 모든 쓰레드가 공유하는데 값을 1씩 증가시키는 오퍼레이션이 thread safe하게 동작하고 있지 않음을 보여주고 있는 것입니다. 이것을 해결하려면 volatile키워드를 사용하면 됩니다.

💻 Programming/Java

[Java] 자바 멀티쓰레드 (Multi Thread)

자바 멀티쓰레드 구현하기

자바에서 쓰레드를 이용하여 비동기로 작업을 처리하는 방법에 대해서 간략하게 포스팅합니다.

 

자바에서 쓰레드를 생성하는 방법은 2가지가 있습니다.

첫 번째는 Runnable 인터페이스를 구현하여 Thread 생성자로 해당 구현체를 넘겨주는 방법이고,

두 번째는 직접 Thread 클래스를 상속하는 것입니다.

 

우선 첫 번째 방법으로 쓰레드를 생성하여  실행하는 코드를 보겠습니다.

    public static void main(String[] args) {
        Runnable task = new Task();
        Thread thread = new Thread(task);
        thread.start();
    }
    static class Task implements Runnable {

        int num = 0;

        @Override
        public void run() {
        	for(int i = 0; i < 10; i++) {
	            System.out.println(num++);
            }
        }
    }

 

위 코드를 실행하면 아래와 같이 출력이 됩니다.

	0
	1
	2
	3
	4
	5
	6
	7
	8
	9

 

이번에는 Thread 클래스를 상속하여 동일한 작업(task)을 하도록 해보겠습니다.

    public static void main(String[] args) {
        ThreadTask task = new ThreadTask();
        task.run();        
    }
    static class ThreadTask extends Thread {

        int num = 0;

        @Override
        public void run() {
        	for(int i = 0; i < 10; i++) {
	            System.out.println(num++);
    	    }
        }
    }

 

실행하면 Runnable로 구현했을 때와 동일하게 아래와 같이 출력이 됩니다.

	0
	1
	2
	3
	4
	5
	6
	7
	8
	9

 

참고로 실제 Thread 클래스를 열어보면 Runnable 인터페이스를 implement하고 있습니다.

public class Thread implements Runnable {
    /* Make sure registerNatives is the first thing <clinit> does. */
    private static native void registerNatives();
    static {
        registerNatives();
    }

    private volatile String name;
    private int            priority;
    private Thread         threadQ;
    private long           eetop;
.
.
.

 

그럼 이번에는 쓰레드 두 개를 동시에 돌려보도록 하겠습니다.

    public static void main(String[] args) {
        Runnable task = new Task();

        Thread thread1 = new Thread(task);
        thread1.start();
        System.out.println("thread 1 executed.");

        Thread thread2 = new Thread(task);
        thread2.start();
        System.out.println("thread 2 executed.");

        System.out.println("쓰레드 콜 종료");
    }

    static class Task implements Runnable {

        int num = 0;

        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                System.out.println(Thread.currentThread().getName() + ", num=" + num++);
            }
        }
    }

 

중간중간에 어떻게 실행이 되는지 확인을 하기 위하여 System.out.println으로 로깅을 해봤습니다.

thread 1 executed.
Thread-0, num=0
Thread-0, num=1
Thread-0, num=2
Thread-0, num=3
Thread-0, num=4
Thread-0, num=5
thread 2 executed.
쓰레드 콜 종료
Thread-0, num=6
Thread-1, num=7
Thread-1, num=9
Thread-0, num=8
Thread-1, num=10
Thread-0, num=11
Thread-1, num=12
Thread-1, num=13
Thread-1, num=14
Thread-1, num=16
Thread-1, num=17
Thread-1, num=18
Thread-1, num=19
Thread-0, num=15

BUILD SUCCESSFUL in 0s
2 actionable tasks: 1 executed, 1 up-to-date

 

위 출력 결과를 보면 쓰레드가 먼저 시작되지만 "task1 executed"가 먼저 출력이 되었고 그 뒤에 첫 번째 쓰레드인 Thread-0이 출력을 시작하였습니다. 그리고 중간에 "task2 executed"가 출력된 걸 보니 두 번째 쓰레드가 실행이 된 것을 알 수 있죠. 두 번째 쓰레드는 Thread-1 이며 첫 번째 쓰레드가 일을 마치기 전에 시작되어 "Thread-1, num=0"을 출력한 것을 확인 할 수 있습니다.

이렇게 하나의 프로세스(main 프로세스) 안에서 여러 개의 작업을 동시에 나누어 실행 할 수 있도록 해주는 것이 바로 이 쓰레드입니다.

쓰레드로 작업을 하게 되면 아래와 같은 특징들이 있습니다.

  • 여러 작업을 동시에 처리할 수 있어 작업을 완료하는데 필요한 총 소요 시간이 줄어든다. (메인쓰레드 1개로 작업했을 때와 비교했을 때)
  • 먼저 시작한 쓰레드가 항상 먼저 일을 끝내지는 않는다. 따라서, 작업의 순서가 중요할 때에는 쓰레드로 나누어 처리하면 안된다.

 

자, 이제 싱글 쓰레드로 10시간 걸릴 일을 100개의 쓰레드를 돌려서 10분만에 끝내고 싶습니다. 어떻게 해야 할까요?

쓰레드를 100개를 만들어야 하는데 아래처럼 무식하게 만들어야 할까요?

        Thread thread1 = new Thread(task);
        Thread thread2 = new Thread(task);
        Thread thread3 = new Thread(task);
        Thread thread4 = new Thread(task);
        Thread thread5 = new Thread(task);
        .
        .
        .

 

아닙니다. 이렇게 해야되면 쓰레드 만들다가 퇴근해야됩니다.

자바에서는 java.util.concurrent패키지에 동시작업을 위해 유용한 클래스들을 모아놨는데 그중에 ThreadPoolExecutor라는 녀석이 있습니다. 이 녀석을 사용하면 두 세 줄이면 100개의 쓰레드를 돌릴 수 있는 코드를 작성할 수 있죠.

ThreadPoolExecutor에 대해 설명하려면 포스트가 길어지니 ThreadPoolExecutor를 이용한 멀티쓰레드 구현서 계속 이어가겠습니다.

 

Converting timestamp to date time string format and vice versa

 

실제 업무에서 java로 프로그래밍 할 때 날짜/시간을 다뤄야 할 때가 참 많습니다.

데이터 업데이트 시간을 기록하거나 로깅을 하거나 등등 말이죠.

그래서 오늘은 시간 변환에 대해서 짧게 한가지만 알려드립니다.

자바 프로그래밍을 시작한지 얼마 안되었을 때 System.currentTimemillis()를 이용해서 내가 작성한 알고리즘이 얼마나 빨리 돌아가는지 확인을 했었는데요, 저 함수의 결과는 long형입니다. 

1970년 1월 1일 UTC 자정 이후로 몇 밀리초가 지났는지를 반환해주죠.

반환값에 대한 정확한 정의는 아래와 같습니다.

   * @return  the difference, measured in milliseconds, between
   *          the current time and midnight, January 1, 1970 UTC.

 

그런데 이 long형 숫자는 길이도 길고 이게 도대체 그래서 몇 일 몇 시 라는 건지를 알아보기가 힘들죠

그래서 이 long형 숫자를 가독성있게 우리가 일반적으로 사용하는 시간 포맷에 맞게 String 타입으로 변환하려면 어떻게 해야 할까요? 그리고 그렇게 얻은 String 타입 시간값을 다시 long형으로 변환하려면 또 어떻게 해야 할까요?

 

우선 long타입 시간을 원하는 일시 포맷으로 변경하는 것은 Date와 SimpleDateFormat을 이용하면 쉽게 변환할 수 있습니다. 아래와 같이 말이죠.

 public static void main(String[] args) {
     Date d = new Date(vv);
     DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
     String bb = format.format(d);
     System.out.println(bb);
 }

 

반대로 String으로 된 일시를 long으로 변환할 때는 아래와 같이 java.sql.Timestamp를 이용하면 쉽게 변환이 가능합니다.

public static void main(String[] args) {
    String prdt = "2020-01-10 10:38:09.419";
    long vv = Timestamp.valueOf(prdt).getTime();
    System.out.println(vv);
}

 

하지만 Timestamp.valueOf(String) 메서드는 "yyyy-mm-dd hh:mm:ss[.fffffffff]" 형태의 string만 입력 가능합니다.

일자만 있거나 시간값만 있으면 사용이 불가능 하다는 것 명심하세요.

만약 일시 포맷을 잘못 입력하면 아래와 같은 오류가 발생합니다.

Exception in thread "main" java.lang.IllegalArgumentException: 
		Timestamp format must be yyyy-mm-dd hh:mm:ss[.fffffffff]

 

java.sql.Timestamp 대신에 LocalDateTime을 이용할 수도 있습니다.

public static void main(String[] args) {

    String prdt2 = "2020-01-11 00:00:00";
    System.out.println(Timestamp.valueOf(prdt2).getTime());
    System.out.println(LocalDateTime.parse("2020-01-11T00:00:00")
        .atZone(ZoneId.of("Asia/Seoul"))
        .toInstant()
        .toEpochMilli());
}

---출력결과---
1578668400000
1578668400000

 

하지만 LocalDateTime의 경우 parse할 때 들어가는 string형태의 일시값에 'T'구분자를 포함해줘야 합니다.

그렇지 않을 경우 아래와 같이 파싱오류가 발생합니다.

Exception in thread "main" java.time.format.DateTimeParseException: 
		Text '2020-01-11 00:00:00' could not be parsed at index 10

 

 

Summary

이번 포스팅에서는 자바에서 long타입의 timestampe를 String 타입의 가독성 좋은 형태로 변환하는 작업과 그렇게 변환된 String을 다시 long으로 변경하는 부분에 대해서 알아보았습니다.

long -> String -> long 변경을 했을 때 동일한 값이 나오는지도 아래 테스트를 통해서 확인할 수 있었습니다.

public static void main(String[] args) {

    // String to long conversion 1
    String prdt = "2020-01-11 10:24:09.419";
    long l1 = Timestamp.valueOf(prdt).getTime();
    System.out.println(l1);

    // String to long conversion 2
    String prdt2 = "2020-01-11T10:24:09.419";
    long l2 = LocalDateTime.parse(prdt2)
        .atZone(ZoneId.of("Asia/Seoul"))
        .toInstant()
        .toEpochMilli();
    System.out.println(l2);

    // long to String conversion
    DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
    System.out.println(format.format(new Date(l1)));
}

---출력결과---
1578705849419
1578705849419 <-- Timestamp를 이용해서 얻은 결과와 동일함을 확인 
2020-01-11 10:24:09.419 <-- long으로 변환했던 String 형태의 시간과 동일하게 출력되는지 확인

 

이상으로 Java에서 datetime을 long에서 String으로 다시 String에서 long으로 변환하는 방법에 대해서 알아보았습니다.

 

유용했다면 공감 꾹 부탁해요~

 

💻 Programming/Java

[Java] 자바 8진수를 10진수로 변환하기

자바에서 8진수 숫자를 사용자(키보드)로부터 입력받아서 10진수로 변환하여 출력하는 예제입니다.


import java.util.Scanner;

public class OctalToDex
{
  public static void main(String[] args)
  {
    Scanner sc = new Scanner(System.in);
    String b=sc.nextLine();
    int a=Integer.valueOf(b, 8);
    sc.close();
    System.out.println(a);
   }
} 


Java에서는 Integer클래스가 존재하여 2진수, 8진수, 16진수의 숫자를 10진수로 쉽게 변환이 가능하며, 그 반대로 10진수를 2진수,8진수,16진수로 변환하는 것을 쉽게할 수 있습니다.

메서드는 아래와 같습니다.
 10진수 -> 2진수 변환 : Integer.toBinaryString(int);
 10진수 -> 8진수 변환 : Integer.toOctalString(int);
10진수 -> 16진수 변환 : Integer.toHexString(int);
 10진수 -> 2진수 변환 : Integer.toBinaryString(int); 
 10진수 -> 8진수 변환 : Integer.toOctalString(int);
 10진수 -> 16진수 변환 : Integer.toHexString(int);​


위 메서드는 10진수 숫자(int)를 2진수/8진수/16진수 스트링으로 반환합니다.

 2진수 -> 10진수 변환 : Integer.valueOf(string, 2);
 8진수 -> 10진수 변환 : Integer.valueOf(string, 8);
16진수 -> 10진수 변환 : Integer.valueOf(string, 10);
2진수 -> 10진수 변환 : Integer.valueOf(string, 2);
8진수 -> 10진수 변환 : Integer.valueOf(string, 8);
16진수 -> 10진수 변환 : Integer.valueOf(string, 10);​


위 메서드는 2진수/8진수/16진수를 나타내는 숫자스트링을 10진수 int로 반환해줍니다.

💻 Programming/Java

[Java] 로또 번호 자동 생성기 만들기

2019년 6월 15일 로또 1등 당첨번호

이번에는 자바로 로또 번호 자동 생성기를 만들어보도록 하겠습니다.

자바로 프로그래밍을 하기전에 우선 로또의 규칙부터 알아야 겠죠.

로또에는 1부터 45까지의 숫자가 존재하고

보너스 번호를 포함하여 총 7개의 숫자를 랜덤하게 뽑습니다.

각 숫자는 중복되어 선택할 수 없습니다.

여기서 키 포인트 단어는 바로 랜덤과 중복 입니다.

자바에서 중복을 제거하는 가장 좋은 방법은 Set을 이용하는 방법입니다.

 

자, 그럼 랜덤하게 숫자를 구하는 것부터 해보도록 하겠습니다.

자바에서 랜덤한 숫자를 얻을 때는 Math.random() 메서드를 이용합니다.

그런데 이 메서드는 0부터 1사이의 double 형태의 소수를 리턴해줍니다.

오잉?? 그럼 어떻게 1부터 45까지의 숫자를 얻는다는 걸까요??

이제부터 트릭을 알려드리겠습니다.

 

Math.random()은 0보다 크거나 같고 1보다 작은 숫자를 반환해줍니다.

내가 얻고자하는 max숫자를 곱해주면

0부터 max값 사이의 double 형태의 숫자를 얻을 수 있습니다.

그럼 이 숫자를 다시 int형태로 casting을 해버리면?

0<= 원하는 숫자 < max 사이의 int 값을 얻을 수 있습니다.

 

예제를 한번 보여드리도록 하겠습니다.

public static void main(String[] args) {
  getRandomNumber();
}
	
private static void getRandomNumber() {
  final int max = 46;
  for(int i = 0; i < 10; i++) {
    int randomNumber = (int)(Math.random() * max);
    System.out.println(randomNumber);
  }
}

위 코드를 실행시키면 아래와 같은 결과를 얻을 수 있습니다.

0
12
34
27
5
21
10
24
43

위 결과에는 중복된 숫자가 나오지 않았지만

몇 번 실행하다보면 동일한 숫자가 연속으로 나오는 경우도 있습니다.

따라서 중복을 제거해주는 과정이 필요하게 됩니다.

이때 필요한 것이 바로 Set입니다.

Set은 자바에서 중복을 제거하고자 할 때 아주 유용하게 쓰이는 자료구조입니다.

Set의 구현체는 여러가지가 있는데 일반적으로 많이 쓰이는 것은 HashSet입니다.

아래 예제 코드를 한번 보겠습니다.

public static void main(String[] args) {
  removeDuplicate();
}
	
private static void removeDuplicate() {
  Set<Integer> noDuplicated = new HashSet<>();
  noDuplicated.add(30);
  noDuplicated.add(30);
  noDuplicated.add(31);
  System.out.println(noDuplicated);
}

위 코드를 실행하면 아래와 같이 출력됩니다.

[30, 31]

보시는 바와 같이 30을 두 번 add 했는데 1개만 저장이 되었습니다.

이것을 이용해서 이미 뽑은 숫자는 저장하지 않고 새로운 번호를 뽑도록 할 수 있습니다.

 

아래는 완성된 로또 번호 생성기의 샘플입니다.

private static void lotto() {
  final int min = 1;
  final int max = 45;
		
  Set<Integer> selected = new HashSet<>();
  while(true) {
    int randomNumber = (int)(Math.random() * (max - min +1) + min);
    if(selected.add(randomNumber)) {
      if(selected.size() == 6) {
        break;
      }
    }
  }
  System.out.println(selected.stream().sorted().collect(Collectors.toList()));
}

위 메서드를 main 함수에서 실행시키면

1~45까지의 숫자들 중에서 중복되지 않은 6개의 숫자를 출력해줍니다.

랜덤 번호 생성하는 부분이 조금 수정된 것을 눈치채셨나요?

저 위에서 보여드린 로직으로는 0이 나올 수 있기 때문에 수정을 한 것입니다.

자바로 랜덤 숫자 구하는 방법에 대한 자세한 내용은 랜덤 숫자 구하기 에서 확인하실 수 있습니다.

 

위 메서드를 10번 실행한 결과는 아래와 같습니다.

[5, 17, 18, 25, 29, 33]
[9, 13, 16, 26, 30, 34]
[21, 24, 27, 30, 31, 42]
[9, 15, 17, 34, 36, 42]
[2, 3, 15, 35, 38, 41]
[8, 16, 30, 31, 36, 39]
[1, 5, 11, 40, 43, 44]
[1, 3, 4, 18, 21, 39]
[4, 7, 19, 28, 38, 40]
[7, 9, 14, 18, 30, 41]

이상으로 자바로 심플한 로또 번호 자동 생성기 만들기 포스팅을 마치도록 하겠습니다.

궁금한 점이 있으시면 댓글 달아주시고,

포스팅 내용이 도움이 되셨다면 공감 꾹 부탁해요 ^-^

 

스트링 거꾸로 뒤집기

 

자바에서 스트링을 거꾸로 뒤집는 간단한 방법을 소개해드립니다.

 

자바에는 각종 array로부터 String을 쉽게 만들 수 있도록 해주는 StringBuilder가 있습니다.

 

생성자에 String을 그대로 넣어서 새로운 스트링을 만들 수도 있을 뿐만 아니라 기본적으로 구현되어있는 reverse 메서드가 있습니다.

 

이 메서드를 이용하면 아래와 같이 단 한 줄로 스트링을 거꾸로 배열할 수 있습니다.

String a = "abcdefg";

String b = new StringBuilder(a).reverse().toString();

System.out.println(a);
System.out.println(b);

출력 결과 

abcdefg

gfedcba

 

아주 간단합니다.

 

💻 Programming/Java

[Java] 랜덤 숫자 구하기

랜덤 숫자들, 출처 : https://openclipart.org/detail/254729/random-numbers-cloud

이번 포스팅에서는 Java로 랜덤한 숫자를 획득하는 방법에 대해서 소개합니다.

 

자바에는 Math 클래스가 존재합니다.

 

해당 클래스에는 다양한 수학적인 계산을 위해 기본적으로 제공해주는 static 메서드들이 여러개 있는데,

그 중에 하나가 random() 메서드입니다.

 

이 메서드는 0에서 1사이의 랜덤한 double 타입 숫자를 반환합니다.

 

javadoc 문서에는 아래와 같이 설명이 나와있습니다.

 

random

public static double random()

Returns a double value with a positive sign, greater than or equal to 0.0 and less than 1.0. Returned values are chosen pseudorandomly with (approximately) uniform distribution from that range.

 

즉, 0.0보다 크거나 같고 1.0보다 작은 double(실수)형 숫자를 반환합니다. 

 

이게 0~1 사이의 수를 반환하면 이 메서드를 이용해서 어떻게 랜덤한 숫자를 얻을 수 있을까요?? 

 

예를 들어 0보다 크거나 같고 100보다 작은 수를 구하고자 한다면 아래와 같이 쓸 수 있습니다.

 

int max = 100;

int randomInt = (int) (Math.random() * max);

 

위 코드에서 (int) (Math.random() * max) 부분은 0 <= 결과값 < max (100) 의 범위 내의 값을 갖게 됩니다.

Math.random()의 최소값이 0이고 최대값이 1.0보다 작기 때문이죠. 

 

이번에는 100을 포함하도록 코드를 수정해 보겠습니다.

int max = 100;

int randomInt = (int) Math.round(Math.random() * max);

 

Math.round() 메서드를 이용하면 0<= 결과값 <= max (100) 범위 내의 값을 얻을 수 있습니다. 

 

하지만 이렇게 할 경우 0과 100이 나올 확률은 1~99가 나올 확률보다 50% 적게 됩니다.

 

0이 나오려면 Math.round()의 값이 0~0.004999...가 나와야 하고

100이 나오려면 0.95~0.9999...가 나와야 합니다.

 

이 경우 0.5%의 확률을 갖게 됩니다.

 

1이 나오려면 0.005~0.014999..가 나오면 되고, 2, 3, 4..., 99 까지는 모두 동일한 확률을 갖게 됩니다.

 

이 경우 1%의 확률을 갖게 되죠.

 

따라서 고르게 분포하는 0~100 사이의 값(경계포함)을 얻으려면 좀 더 고민을 해야합니다.

 

그럼 어떻게해야 0~100 사이의 숫자를 모두 동일한 확률로 얻을 수 있을까요??

 

int max = 100;
int randomInt = (int) (Math.random() * (max + 1));

간단합니다. max를 포함하고자 할 경우 max + 1을 곱해주면 만사OK입니다. 

 

자, 그럼 최소값의 범위를 정해주고 싶으면 어떻게 해야 할까요?

 

int min = 90, max = 100;
int randomInt = (int) (Math.random() * (max + 1 - min)) + min;

위 처럼 해주시면 됩니다.

 

즉, 랜덤하게 최대값에서 최소값을 뺀 만큼의 숫자를 만든 뒤에 최소값을 더해주는거죠. 

 

여기서는 최대값 100에서 1을 더하고 최소값 90을 빼서 최소 0~ 최대 10이 나오도록 만들었습니다. 

 

거기다가 min(90)값을 더해주면 0+90 ~ 10+90 사이의 수, 즉, 90~100 사이의 수를 얻을 수 있게되죠. 

 

하나하나 따라가니 어렵지 않죠?

 

오늘도 즐거운 코딩하시기 바랍니다~

 

💻 Programming/Java

[Java] 숫자 판별하기

 

자바에서 숫자 판별하기

 

Java의 스트링이 숫자(정수, int)인지 판단하기 위한 방법 두 가지를 소개합니다

 

 

1) 스트링의 각 문자를 하나하나 순회하면서 ascii 코드 값을 비교하는 방법

 

첫 번째로 소개해드릴 방법은 입력받은 문자열(스트링)의 각 문자가 0~9 ascii 코드값 사이에 있는 char인지를 판별하는 방법입니다.

 

0~9의 ascii 코드값은 십진수로 48~57 입니다.

 

따라서 String을 char[]로 변환한 다음 loop를 돌면서 각 char가 48~57사이의 값인지를 판단하여 숫자인지를 판별합니다.

 

코드는 아래와 같습니다.

String str = "not a number";

boolean isNumber = true;

for(char c : str.toCharArray()) {

  if(c >= 48 && c<= 57) {
        continue;
  } else {
        isNumber = false;
        break;
  }
}
System.out.println("Is string a number ? answer: " + isNumber);

 

2) Integer.parseInt 를 이용하는 방법

 

두 번째 방법은 Integer.parseInt 메서드를 이용하는 방법입니다.

 

parseInt 메서드에 대한 javadoc 문서에는 아래와 같이 설명이 나와있습니다.

public static int parseInt(String s)
                    throws NumberFormatException
Parses the string argument as a signed decimal integer. The characters in the string must all be decimal digits, except that the first character may be an ASCII minus sign '-' ('\u002D') to indicate a negative value. The resulting integer value is returned, exactly as if the argument and the radix 10 were given as arguments to theparseInt(java.lang.String, int) method.

 

Parameters:
s - a String containing the int representation to be parsed
Returns:
the integer value represented by the argument in decimal.
Throws:
NumberFormatException - if the string does not contain a parsable integer.

 

 

즉, 문자로 표현된 숫자를 입력받아 int로 return하는데요

입력받은 스트링이 숫자가 아닐 경우 NumberFormatException예외를 발생시킵니다.

 

따라서 위 메서드를 사용하여 NumberFormatException의 발생 여부에 따라 해당 스트링이 숫자인지 아닌지를 판별할 수 있습니다.

 

이 방식을 사용한 코드는 아래와 같습니다.

 

String str = "421303";

boolean isNumber = false;

try {

Integer.parseInt(str);

isNumber = true;

} catch (NumberFormatException e) {

// do nothing

}

System.out.println("Is string a number ? answer: " + isNumber);

 

Integer 뿐만 아니라 다른 wrapper 클래스들에도 Long.parseLong, Double.parseDouble 메서드들이 있으니 참고하시기 바랍니다.

 

 

위 두 가지 방법 외에 또 좋은 방법이 있으신 분들 제보받습니다 ㅎ

 

내용이 도움이 되셨다면 공감 누르고 가주세요~

 

 

 

 

💻 Programming/Java

AWS S3 버킷에 파일 업로드하기 (자바)


  AWS SDK Java jar 파일 다운 받기

AWS-SDK for Java - https://aws.amazon.com/ko/sdk-for-java/

위 링크를 따라 들어가면 우측 상단에 SDK다운로드 또는 이클립스용 툴킷을 다운로드 받을 수 있는 버튼이 있습니다. 저는 메이븐을 사용할건데 직접 다운로드 받거나 툴킷을 써보고 싶으신 분들은 위 링크를 이용해주세요.


maven을 이용한다면 

1
2
3
4
5
<dependency>
    <groupId>com.amazonaws</groupId>
    <artifactId>aws-java-sdk</artifactId>
    <version>1.11.386</version>
</dependency>


이 글이 포스팅 되는 시점에 최신버전은 1.11.388입니다. minor 버전이 하루가 다르게 증가하고있어요 ㅎ



  AWS s3 파일 업로드 하기(AWS S3 Upload for java )

실제로 S3에 업로드를 하기 위해서는 S3에 권한이 필요합니다. 이 권한을 얻기 위해서는 ACCESS_KEY, SECRET_KEY 를 생성해야 하는데 이는 아래 링크를 참고해주세요.

# Access Key, Secret Key 생성방법 - http://keichee.tistory.com/298



사용방법은 간단합니다.

아래처럼 파일을 전달받아 아마존 S3에 accesskey와  secretkey를 이용하여 권한을 얻고 파일을 업로드 하면됩니다. 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class AWSService {
    private static final String BUCKET_NAME = "bucket_name";
    private static final String ACCESS_KEY = "ACCESS_KEY";
    private static final String SECRET_KEY = "SECRET_KEY";
    private AmazonS3 amazonS3;
 
    public AWSService() {
        AWSCredentials awsCredentials = new BasicAWSCredentials(ACCESS_KEY, SECRET_KEY);
        amazonS3 = new AmazonS3Client(awsCredentials);
    }
 
    public void uploadFile(File file) {
        if (amazonS3 != null) {
            try {
                PutObjectRequest putObjectRequest =
                        new PutObjectRequest(BUCKET_NAME + "/sub_dir_name"/*sub directory*/, file.getName(), file);
                putObjectRequest.setCannedAcl(CannedAccessControlList.PublicRead); // file permission
                amazonS3.putObject(putObjectRequest); // upload file
 
            } catch (AmazonServiceException ase) {
                ase.printStackTrace();
            } finally {
                amazonS3 = null;
            }
        }
    }
}
 




자바로 개발을 하다가 OOM이 발생하는 경우가 발생하면 힙메모리가 어느 지점에서 증가하는지 파악을 해야한다. 확인하는 방법은 크게 두 가지 방법이 있다. 소스레벨 수정이 가능한 경우와 소스레벨 수정이 불가능한 경우로 나뉘는데, 소스레벨 수정이 불가능하면 자바 힙 덤프를 떠서 확인을 할 수 있다. 이번 포스팅에서는 소스레벨 수정이 가능한 경우, 즉, 개발 시점에서 확인하는 방법을 얘기해보려 한다.


자바는 개발자들에게 유용한 라이브러리들은 기본적으로 제공하고있으며, 메모리 사용량 관련하여 Runtime 클래스에서 메서드를 제공하고있다.


Java 8 API 문서를 보면 아래와 같이 설명이 되어있다.


Class Runtime



  • public class Runtime
    extends Object
    Every Java application has a single instance of class Runtime that allows the application to interface with the environment in which the application is running. The current runtime can be obtained from the getRuntime method.

    An application cannot create its own instance of this class.

즉, 모든 자바 프로그램들은 하나의 Runtime 인스턴스를 가지고 있는데, 이 Runtime인스턴스는 프로그램이 실행되고있는 환경과 인터페이스할 수 있도록 해준다. 즉, 자바프로그램이 실행되고있는 시스템의 정보를 가져올 수 있다는 것이다. (명령어 실행도 가능하다.)


그럼 Runtime 클래스에서 어떤 메서드들을 제공하는지 한번 보자.


Modifier and Type

Method and Description
voidaddShutdownHook(Thread hook)
Registers a new virtual-machine shutdown hook.
intavailableProcessors()
Returns the number of processors available to the Java virtual machine.
Processexec(String command)
Executes the specified string command in a separate process.
Processexec(String[] cmdarray)
Executes the specified command and arguments in a separate process.
Processexec(String[] cmdarray, String[] envp)
Executes the specified command and arguments in a separate process with the specified environment.
Processexec(String[] cmdarray, String[] envp, File dir)
Executes the specified command and arguments in a separate process with the specified environment and working directory.
Processexec(String command, String[] envp)
Executes the specified string command in a separate process with the specified environment.
Processexec(String command, String[] envp, File dir)
Executes the specified string command in a separate process with the specified environment and working directory.
voidexit(int status)
Terminates the currently running Java virtual machine by initiating its shutdown sequence.
longfreeMemory()
Returns the amount of free memory in the Java Virtual Machine.
voidgc()
Runs the garbage collector.
InputStreamgetLocalizedInputStream(InputStream in)
Deprecated. 
As of JDK 1.1, the preferred way to translate a byte stream in the local encoding into a character stream in Unicode is via the InputStreamReader and BufferedReader classes.
OutputStreamgetLocalizedOutputStream(OutputStream out)
Deprecated. 
As of JDK 1.1, the preferred way to translate a Unicode character stream into a byte stream in the local encoding is via the OutputStreamWriterBufferedWriter, and PrintWriter classes.
static RuntimegetRuntime()
Returns the runtime object associated with the current Java application.
voidhalt(int status)
Forcibly terminates the currently running Java virtual machine.
voidload(String filename)
Loads the native library specified by the filename argument.
voidloadLibrary(String libname)
Loads the native library specified by the libname argument.
longmaxMemory()
Returns the maximum amount of memory that the Java virtual machine will attempt to use.
booleanremoveShutdownHook(Thread hook)
De-registers a previously-registered virtual-machine shutdown hook.
voidrunFinalization()
Runs the finalization methods of any objects pending finalization.
static voidrunFinalizersOnExit(boolean value)
Deprecated. 
This method is inherently unsafe. It may result in finalizers being called on live objects while other threads are concurrently manipulating those objects, resulting in erratic behavior or deadlock.
longtotalMemory()
Returns the total amount of memory in the Java virtual machine.
voidtraceInstructions(boolean on)
Enables/Disables tracing of instructions.
voidtraceMethodCalls(boolean on)
Enables/Disables tracing of method calls.


위 메서드들이 Runtime 클래스에서 제공하고있는 메서드들이다.

이 중에서 메모리 관련 메서드들이 몇 개 보인다.

첫 번째로 freeMemory가 있는데, 이 메서드는 힙메모리 영역에서 free메모리를 바이트단위로 계산해서 반환해준다. 그리고 maxMemory와 totalMemory가 있는데 totalMemory는 현재 애플리케이션이 사용하고있는 총 힙 메모리를 의미하며, maxMemory는 OOM(OutOfMemory)예외가 발생하는 메모리 사이즈를 반환해준다. 역시 바이트 단위이며, 애플리케이션이 이 메모리 한계를 넘어서는 순간 OOM이 발생하면서 프로그램 실행이 중단된다.


사용예를 보면 아래와 같다.


// 현재 힙 메모리 사이즈를 바이트 단위로 반환

long heapSize = Runtime.getRuntime().totalMemory(); 


// 애플리케이션에 할당된 힙메모리 사이즈. 이 사이즈를 넘어서면 OOM 발생

long heapMaxSize = Runtime.getRuntime().maxMemory();


// 현재 남아있는 free메모리. 프로그램이 실행되는 동안 증감을 반복

long heapFreeSize = Runtime.getRuntime().freeMemory();


해당 사이즈를 반환받은 뒤 KB, MB단위로 변환해주는 메서드를 만들어서 콘솔에 출력해주면 읽기가 편하다.

안녕하세요, 케이치입니다.


이번 포스팅에서는 자바로 텍스트 파일의 내용을 읽어서 출력해보는 소스를 보여드리겠습니다.


우선 CLI 환경이든 다른 IDE 툴 환경이든 Java 프로그래밍을 실행하려면 메인 함수가 필요하죠.


그래서 클래스 파일을 만들면 public void main(String[] args) {} 함수를 생성해서 쓰죠.


이때  main메서드의 인자로 받는 저 String[] args 가 파일명을 입력받기 위한 통로입니다.


커맨드 라인 명령으로 java myapp a.txt  라고 입력을 해서 실행하면 저 args에 a.txt라는 스트링 값이 들어가게 됩니다.


즉, 파일명을 입력받게 되는 것이죠.


파일명을 입력받았으면, 우리는 그 파일을 열어서 안에 있는 내용을 출력하기만 하면 되는 겁니다.


그렇다고 무작정 파일을 열 수는 없을 겁니다. 만약 그 파일이 존재하지 않으면?? 에러 처리도 해줘야 겠죠?


자, 그럼 하나하나 차근차근 해 볼까요?


우선 클래스를 하나 생성하고 메인 함수를 만들어 봅시다.


public class ReadFileAndPrint {     public static void main(String[] args) {     } }


ReadFileAndPrint라는 이름의 자바파일을 하나 생성해서 메인함수를 정의했습니다.


자, 그럼 이제 뭘 해야 할 까요? 저 위에서 말씀드린 것처럼 파일명을 입력받아서 args로 전달해주는 것은 자바에서 알아서 자동으로 해줄테니


우리는 그 전달받은 파일명을 가지고 지지고 볶고 하면 되겠죠?


일단 입력 받은 파일명이 존재하는지를 확인해서 에러 처리를 해줘야겠습니다.



public static void main(String[] args) {
		
	// 1. 입력받은 파일이 있는지 검사
	if ( args.length == 0 ){
		System.out.println("입력받은 파일이 없습니다.");
		System.exit(0);
	}
}


위 코드는 args로 전달받은 값이 있는지 스트링 배열의 길이를 검사해서 입력받은 값이 없으면 메시지를 출력하고 프로그램을 종료하도록 해놓았습니다.


자, 그럼 실제로 입력 받은 값이 있을 때는 어떻게 해야 할 까요?


그 입력받은 값으로 파일을 읽어들여야 겠죠?


이제 아래 코드를 추가합니다.



// 2. 입력받은 파일이 존재하는지 검사
File file = new File(args[0]);

if ( file.exists() ){

}


입력받은 파일이 한개라는 가정 하에 args배열의 0번째 인덱스에 있는 값만 사용하고 있습니다.


파일을 자바소스로 읽어들일 때는 File 객체를 사용합니다. File 생성자에 파일명을 담고있는 args[0] 을 전달하여 new 키워드로 생성하면 해당 이름의 파일을 File 객체로 만들어 줍니다.


그리고 if 문을 통해서 해당 파일명을 갖는 파일이 실제로 시스템 상에 존재하는지 확인을 합니다.


if 문 안에서는 해당 파일명을 갖는 파일이 실제로 존재했을 때 해야할 일을 코드로 적어주면 되겠죠.


우리는 File  객체를 BufferedReader 를 이용해서 좀더 다루기 쉬운 형태로 바꿀 겁니다.


이제 if 문 안에 다음 소스를 추가해 볼까요?



// 3. 텍스트 파일의 내용을 읽어서 출력 BufferedReader br = new BufferedReader(new FileReader(file)); while( br.ready() ){ System.out.println(br.readLine()); } br.close();


위 코드를 보면 File 객체인 file을 FileReader로 감싼 다음 다시 BufferedReader로 감쌌습니다.


이렇게 하면 BufferedReader 의 readLine() 메서드를 이용해서 손쉽게 라인 단위로 파일을 읽어들일 수 있습니다.


내용이 존재하는지는 br.reader() 를 이용해서 검사를 하고 true가 반환될 경우에 계속해서 한줄씩 읽어내려가면서 출력하도록 로직이 구성되어있음을 확인할 수 있습니다.


자, 그럼 전체 소스를 다시 한번 보도록 하죠.



public class ReadFileAndPrint {     public static void main(String[] args) throws IOException {

// 1. 입력받은 파일이 있는지 검사 if ( args.length == 0 ){ System.out.println("입력받은 파일이 없습니다."); System.exit(0); } // 2. 입력받은 파일이 존재하는지 확인 File file = new File(args[0]); if ( file.exists() ){     // 3. 파일이 존재하면, 텍스트 파일의 내용을 읽어서 출력     BufferedReader br = new BufferedReader(new FileReader(file));     while( br.ready() ){ System.out.println(br.readLine());     }     br.close(); }

}



이제 자바 클래스 파일을 컴파일하고 실행할 때 인자로 원하는 텍스트 파일의 절대경로명을 넣어주세요. 


상대경로명을 넣을 경우 환경에 따라 파일을 못 찾을 수 있습니다.


파일의 내용이 잘 출력된다면 잘 따라오신겁니다.


어때요 ? 별로 어렵지 않죠??


이상으로 자바로 텍스트 파일 읽어서 출력하기 포스팅을 마치겠습니다.


궁금하신 점 있으면 댓글달아주세요 ^-^

자바 프로그램을 짜다보면 현재 프로젝트의 root 경로를 필요로 할 때가 있다.


그럴 경우 아래처럼 


public static void main(String[] args) {
       
      System.out.println("Current Working Directory = " + System.getProperty("user.dir"));
}

System.getProperty 메서드에 user.dir 을 인자로 넣어주면 현재 프로젝트의 root 경로(absolute path)를 String 으로 반환합니다.


Use 'System.getProperty("user.dir")' method for getting current working directory as absolute path. The method returns a string value of the root path of the java project as an absolute path.



이클립스 사용시 웹앱 프로젝트를 처음 만들면 이 에러를 볼 수 있습니다.


이 에러는 서블릿 클래스가 클래스 빌드패스에 잡혀있지 않아서 발생하는 문제입니다.


아래와 같이 해결하시면 됩니다.


Project Properties-> Java Build Path-> Add Library -> Select "Server Runtime" from the list-> Next->Select "Apache Tomcat"-> Finish

CentOS 6를 처음 설치하면 Open JDK가 기본적으로 설정되어있다. 하지만 개발자들이 쓰기에는 그닥 적합하지 않은것 같다. 이런저런 문제도 좀 있는것 같고. 그래서 찾아보다가 alternatives에 대해서 보게되었다.


[root@mycom ~]# alternatives


대체 버전 1.3.49.3 - Copyright (C) 2001 Red Hat, Inc.
GNU Public License하에서 이 프로그램을
자유롭게 재배포 할 수 있습니다.
사용법: alternatives --install <링크> <이름> <경로> <우선순위>
                    [--initscript <서비스>]
                    [--slave <링크> <이름> <경로>]*
       alternatives --remove <이름> <경로>
       alternatives --auto <이름>
       alternatives --config <이름>
       alternatives --display <이름>
       alternatives --set <이름> <경로>

일반 옵션: --verbose --test --help --usage --version
                --altdir <디렉토리> --admindir <디렉토리>


여기서 저 alternatives라는 실행파일의 실제경로는 /usr/sbin/alternatives 이다.


요놈이 무슨 일을 하느냐하면 링크를 생성하는데 이 링크의 대상이 되는 녀석들을 옵션으로 여러개를 저장을 해놓았다가 필요할 때 마다 바꿔가며 쓸 수 있다는 것이다.


그럼 지금 내 컴퓨터에는 java명령어와 연결되어있는 실행파일들이 몇개나 되는지 한번 볼까?


[root@mycom ~]$ /usr/sbin/alternatives --config java

1 개의 프로그램이 'java'를 제공합니다.

  선택    명령
-----------------------------------------------
*+ 1           /usr/lib/jvm/jre-1.6.0-openjdk.x86_64/bin/java

현재 선택[+]을 유지하려면 엔터키를 누르고, 아니면 선택 번호를 입력하십시오:


자, 이런식으로 선택할 수 있는 옵션이 나온다.


이제 선택옵션을 하나 더 추가해보자.


[root@Emerald ~]# alternatives --install /usr/bin/java java /usr/java/jdk1.6.0_45/bin/java 2

[root@Emerald ~]# alternatives --config java

2 개의 프로그램이 'java'를 제공합니다.

  선택    명령
-----------------------------------------------
*+ 1           /usr/lib/jvm/jre-1.6.0-openjdk.x86_64/bin/java
   2           /usr/java/jdk1.6.0_45/bin/java

현재 선택[+]을 유지하려면 엔터키를 누르고, 아니면 선택 번호를 입력하십시오:2


alternatives --install 명령을 이용하여 /usr/bin/java 링크에 /usr/java/jdk1.6.0_45/bin/java를 java라는 이름으로 연결을 시켰고 우선순위를 2로 주었다. 그리고 alternatives --config 명령을 이용해서 선택을 2번으로 변경했다.


이렇게 옵션으로 명령어의 링크를 관리할 수 있기 때문에 나름 유용한 팁이 아닐까 싶다.


더 자세한 내용은 구글링이나 man페이지를 읽어보시면 됩니다~~~









자바는 JVM을 시스템 위에 올려서 애플리케이션을 실행하기 때문에 플랫폼에 독립적입니다.


그런데 라인구분자는 윈도우 계열이냐 유닉스 계열이냐에 따라 다릅니다.


이럴때 자바에서는 시스템 프로퍼티로 라인구분자가 뭔지를 읽어올 수 있습니다.


System.getProperty("line.separator");

위 코드를 사용하면 현재 시스템에서 사용되는 라인구분자를 String 으로 얻어올 수 있습니다.


💻 Programming/Java

[ Java / 자바 ] 현재 날짜 및 시간 구하기

자바에는 Date클래스가 두 종류가 있다.

java.util.Date와 java.sql.Date. 이 두 가지 차이점도 알아보고 현재 날짜 및 시간도 구해보자.

아래 소스는 테스트를 위한 소스이다.

 

public class SimpleDateTest {
    public static void main(String[] args) {
         

        // 1. util.Date로 얻어온 현재시간을 SimpleDateFormat을 이용해서 연도, 월, 일, 시간, 분, 초 까지 표현하도록 해보았다. 붉은 색으로 표시된 부분은 자신이 원하는 포맷으로 변경이 가능하다. 예를들면 "yy/MM/dd"와 같은 형태로 말이다.
        String currentDate = new SimpleDateFormat("yyMMddhhmmss").format(new java.util.Date());
        System.out.println(currentDate);

 

        // 2. sql.Date로 언어온 현재시간을 1번과 동일하게 출력해본다. sql.Date는 생성시 long타입의 시간값을 요구한다. System.currentTimeMillis()는 현재시간을 long타입으로 반환해주므로 이를 이용했다.  

        currentDate = new SimpleDateFormat("yyMMddhhmmss").format(

                                                    new java.sql.Date(System.currentTimeMillis()));
        System.out.println(currentDate); 


        // 2. util.Date를 이용하여 얻어온  Date
        Date date = new java.util.Date();
        System.out.println(date);

 

        // 3. sql.Date를 이용하여 얻어온 Date
        Date sqlDate = new java.sql.Date(System.currentTimeMillis());
        System.out.println(sqlDate);
    }


💻 Programming/Java

[Java] 자바로 만든 구구단 소스

루프를 한번 만 사용한 자바 구구단 소스


자바로 구구단 소스를 작성해보았습니다.

 

continue, break문을 사용하지 않고, 루프도 중복 루프를 사용하지 않고 하나의 loop문을 사용한 구구단입니다. 


Below java source code prints out multiplication table. 

It does not use nested-loop. It only uses one for-loop. 



public class gugudan {

public static void main(String args[]){

     System.out.println("구구단입니다.");
     int i = 1,b = 1;

     while ( i < 10 ) {
          if( b == 10 ) {

              i+=1; 

              b=1;

          }
          if ( i != 10 ) { 

              System.out.println(i+"*"+b+"="+i*b);
              b++;
          }
     }
}

}


💻 Programming/Java

[알고리즘/문제풀이] CodingBat Array-3 fix34

원본 문제는 이곳에서 확인이 가능합니다.


간략하게 한글로 문제를 번역하면 아래와 같습니다.


int[]를 인자로 받아서 3 바로 뒤에 4를 위치하도록 정렬한 뒤 결과를 리턴합니다.

인자로 들어온 int[]에서 숫자 3과 숫자4의 개수는 항상 동일하며, 숫자 3 뒤에는 항상 3과 4가 아닌 다른 수가 들어옵니다. 숫자3은 정렬할 수 없으며 다른 모든 수 들은 위치변경이 가능합니다. 또한, 첫 숫자 3은 항상 숫자 4보다 먼저 출현합니다.


보통 int[]보다는 List형태의 데이터를 다루기가 쉽습니다. 기본적으로 제공해주는 api가 사용하기 쉽기 때문이죠.

그래서 List를 사용했습니다.

우선 int[] 를 루프를 돌려서 (3 이 출현하는 위치 + 1)과 (4의 위치)가 어디인지를 두개의 ArrayList에 나눠서 넣었습니다.

어차피 3과 4의 출현 빈도가 동일하기 때문에 두개 리스트의 길이는 항상 동일하겠죠.

그렇게 루프를 한번 돌면서 위치정보를 갖고있다가, 위치정보 리스트를 루프돌면서 해당 위치의 숫자들의 위치를 서로 바꿔주면 되는 것이죠. ( 3의 위치 +1 )을 저장하는 이유는 3 바로 다음의 숫자와 4의 위치를 서로 바꿔줘야 하기 때문입니다.


저는 여기서 리스트를 두개를 사용했는데, 리스트하나에 맵객체를 넣어서 구현할 수도 있겠습니다. 맵에는 ( 3의 위치+1)과 4의 위치가 들어가겠죠.


public int[] fix34(int[] nums) {
  List<Integer> posOfFour = new ArrayList<Integer>();
  List<Integer> posOfThree = new ArrayList<Integer>();
  for ( int i = 0; i < nums.length; i++ ){
      if ( nums[i] == 4 ){
        posOfFour.add(i);
      }
      if ( nums[i] == 3 ){
         posOfThree.add(i+1);
      }
  }
  for ( int j = 0; j < posOfThree.size(); j++ ){
     int temp = nums[(int)posOfThree.get(j)];
     nums[(int)posOfThree.get(j)] = nums[(int)posOfFour.get(j)];
     nums[(int)posOfFour.get(j)] = temp;
  }
  return nums;
}