Java (27)

💻 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처럼 가변축소를 수행하는 메서드는 병렬연산에 적합하지 않다고 합니다. 참고하시기 바랍니다.

문장 내에서 사용된 distinct 문자 개수 구하기

한 문장 안에서 사용된 distinct 문자의 개수를 구해야 한다면 어떻게 할 수 있을까요?

stream이 나오기 전이었다면 그저 String을 캐릭터 배열로 만들어서 loop를 돌려 set에 넣은 뒤 set의 사이즈를 구하면 됐겠죠.

아래처럼 말이죠.

    String sentence = "Computer users take it for granted that their systems can do more than one thing at a time.";
    
    Set<Character> s = new HashSet<>();
    for (char c : sentence.toCharArray()) {
    	s.add(c);
    }
    
    System.out.println(s.size());

하지만 stream 을 이용하면 한줄로 해결이 가능합니다.

 

Stream을 이용한 distinct 문자 개수 구하기

stream에는 distinct() 메서드가 있으며 이는 해당 스트림내에서 distinct한 것들만 추출해줍니다. 그리고 count()메서드를 이용하여 그 개수를 셀 수 있습니다.

그래서 위에서 set과 for-loop를 사용한 부분을 stream을 이용하여 한줄로 줄이면 아래와 같이 바꿀 수 있습니다.

    String sentence = "Computer users take it for granted that their systems can do more than one thing at a time.";

    long distinctCharsCount = sentence.chars().distinct().count();

    System.out.println(distinctCharsCount);

훨씬 간단하게 구할 수 있습니다.

 

 

 

1차원 배열 생성에 대한 내용을 아직 안보셨다면 보고 오세요~ >> 1차원 배열 생성(선언 및 초기화)

1차원 배열이 1열로 된 저장공간이었다면 2차원 배열은 matrix(행렬)을 생각하시면 됩니다.

 

2차원 배열 선언

자바에서 2차원 배열은 아래와 같이 선언할 수 있습니다.

    public static void main(String[] args) {
        int[][] array;  // O
        int [][]array;  // X
        int array[][];  // X
    }

지난 1차원 배열 생성 시와는 다르게 제일 위의 방법으로만 문법적 오류 없이 정상적으로 2차원 배열을 선언할 수 있습니다.

 

 

2차원 배열의 초기화

2차원 배열을 초기화 할 때는 아래와 같이 합니다.

    public static void main(String[] args) {

        int[][] array;  // 2차원 배열의 선언

        array = new int[1][5];	// 2차원 배열의 초기화
    }

 

2차원 배열의 선언과 초기화를 동시에 하는 방법

2차원 배열도 1차원 배열처럼 선언과 초기화를 동시에 할 수 있습니다.

    public static void main(String[] args) {
        
        int[][] array = new int[1][5];  // 2차원 배열의 선언과 초기화를 한 번에

    }

 

이렇게 하면 배열 내에는 0으로 기본값이 들어가게 됩니다.

 

1차원 배열과 마찬가지로 아래처럼 초기화도 가능합니다.

    public static void main(String[] args) {

        int[][] array = {{1,2,3}, {4,5,6}};

    }

이렇게 초기화를 한다는 것은 기본값을 하드코딩하여 정해주겠다는 것이겠죠.

 

자, 배열을 선언하고 공간을 만들어 주는 작업을 완료했습니다.

이제 배열에 저장된 내용을 출력하는 것을 한 번 보겠습니다.

 

2차원 배열 출력하기

1차원 배열을 출력할 때는 Arrays.toString() 메서드를 사용했었습니다.

하지만 2차원 배열을 출력할 때는 그 메서드를 사용할 수가 없습니다.

왜냐면 2차원 배열은 배열 안에 배열이 있는 형태이기 때문입니다.

그리고 배열은 기본적으로 Object 이고 Object의 toString이 호출되어 원하는 결과를 출력해주지 않습니다.

따라서 별도로 출력문을 구현해야합니다.

쉽게하려면 아래처럼 loop를 한번 돌리면서 출력을 할 수 있습니다.

    public static void main(String[] args) {

        int[][] array = new int[8][9];  // 구구단 결과값 저장을 위한 2차원 배열의 선언 및 초기화

        for (int i = 0; i < array.length; i++) {
            System.out.println(Arrays.toString(array[i]));
        }
    }

 

그럼 연습삼아 2차원 배열안에 구구단의 결과를 저장해보도록 해볼게요.

 

    public static void main(String[] args) {

        int[][] array = new int[8][9];  // 구구단 결과값 저장을 위한 2차원 배열의 선언 및 초기화

	// 배열에 구구단의 결과값을 저장
        for (int i = 2; i < 10; i++) {
            for (int j = 1; j < 10; j++) {
                array[i-2][j-1] = i * j;
            }
        }

	// 배열에 저장된 내용을 출력
        for (int i = 0; i < array.length; i++) {
            System.out.print((i + 2) + "단: ");
            System.out.print(Arrays.toString(array[i]));
            System.out.println();
        }
    }
    
    
    // 출력 결과
    2단: [2, 4, 6, 8, 10, 12, 14, 16, 18]
    3단: [3, 6, 9, 12, 15, 18, 21, 24, 27]
    4단: [4, 8, 12, 16, 20, 24, 28, 32, 36]
    5단: [5, 10, 15, 20, 25, 30, 35, 40, 45]
    6단: [6, 12, 18, 24, 30, 36, 42, 48, 54]
    7단: [7, 14, 21, 28, 35, 42, 49, 56, 63]
    8단: [8, 16, 24, 32, 40, 48, 56, 64, 72]
    9단: [9, 18, 27, 36, 45, 54, 63, 72, 81]

 

로직을 한번 보면 크게 구구단을 저장할 때와 저장된 내용을 출력하는 부분으로 구분했습니다. 그리고 for-loop문의 조건걸에 하드코딩한 숫자를 사용하기도 하고 array.length 를 사용하기도 했습니다. 가급적 array.length 의 사용을 권장하며 2차원 배열에서 array.length는 행이 몇 개가 존재하는지를 반환하고, array[x].length는 열의 개수를 반환합니다. 구구단은 보통 2단부터 9단까지이기 때문에 배열을 초기화할 때 사이즈를 8행, 9열로 정의를 하였고, array.length 는 8, array[x].length 는 9 가 됩니다.

 

 

이상으로 자바에서 2차원 배열을 생성하고 초기화하고 실제로 데이터를 저장한 뒤 출력하는 것 까지 살펴보았습니다.

질문있으시면 댓글 달아주세요~

 

도움이 되셨다면 공감~ 꾸~~~욱 눌러주세요 ^-^

감사합니다~

§ 쓰레드 기본 내용에 대해서는 [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]

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

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

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

 

💻 Programming

스프링부트 스케쥴러 사용하기

스프링부트 스케쥴러

이번 포스팅에서는 스프링부트 프로젝트에서 스케쥴링 작업을 등록하여 사용하는 방법에 대해서 설명합니다.

스프링 부트에서 스케쥴러를 사용하려면 우선 아래처럼

@EnableScheduling 어노테이션을 @Configuration이 붙은 클래스에 등록해줘야 합니다.

 

스케쥴링 활성화를 위한 @EnableScheduling 사용

 

위 처럼 어노테이션을 붙여주면

스프링이 관리하는 빈 중에서 아래와 같이

@Scheduled 어노테이션이 붙어있는 것들을

찾아서 활성화 시켜주는 역할을 하게됩니다.

 

위 처럼 @Scheduled 어노테이션을 붙여주고 실행주기를 특정지어주면

해당 애플리케이션이 실행되면 자동으로 실행이 됩니다.

 

실행주기를 설정하는 방법은 기본적으로 세 가지가 있습니다.

 

fixedRate : 매 특정 밀리초마다 동작

fixedDelay : 해당 기능이 종료된 후 특정 밀리초 이후에 다시 동작

cron : 크론표현식에 정해진 내용대로 동작

 

여러 개의 스케쥴 잡을 등록할 때에는 주의할 점이 있습니다.

위 처럼 두 개의 스케쥴 잡이 등록되어있을 경우 한 번에 하나의 잡만 동작한다는 점입니다.

즉, @Scheduled가 붙은 기능들이 실행되는 시간이 중복될 경우 한 번에 하나의 작업만 실행됩니다.

 

만약 두 개 이상의 기능이 한꺼번에 실행되어도 성능에 문제가 없을 경우에는

아래처럼 @Async처리를 할 수 있습니다.

 

@Async 처리한 스케쥴 tasks

 

물론, @Async 가 적용되려면 @Configuration에 @EnableAsync도 추가해줘야 합니다.

 

여기까지 설정이 되었다면 위 두 scheduled task들은 동시에 실행됩니다.

 

추가로 @Async를 붙이지 않은 task를 하나 더 추가하면 어떻게 동작할까요?

task를 하나 더 추가해서 꼭!! 테스트해보세요.

 

이상으로 스프링부트에서 스케쥴링 잡을 등록하여 활용하는 방법에 대해 간단히 포스팅 해보았습니다.

유용했다면 좋아요 꾹!꾹!꾹! 눌러주세요 ^-^

💻 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단위로 변환해주는 메서드를 만들어서 콘솔에 출력해주면 읽기가 편하다.

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


오늘도 쉽게 넘어가지를 않고 에러가 발생하네요. 오늘은 윈도우용 도커를 설치를 했다가 jre 8 이 정상적으로 동작을 하지 못하게 된 케이스입니다.


jdk7, 8, jre7, 8을 윈도우10 에 설치해서 사용중인 환경인데요 jdk8을 설치해보신 분들은 아시겠지만 7버전 까지는 c:\Program Files\Java 밑에 설치가 되고 환경설정 변수에도 해당 경로의 bin디렉토리를 설정해줬었는데(C:\Program Files\Java\jre7\bin), 8버전부터는 C:\ProgramData\Oracle\Java\javapath\java.exe 를 환경변수에 가지도록 해놨더군요. 물론 설치 경로는 Program Files\Java\jdk1.8 이었는데도 불구하고 말이죠. 어찌되었건 잘 쓰고있었는데, 문제가 생긴건 챗봇 오픈소스 테스트를 하려고 윈도우용 도커를 설치해서 테스트를 하고난 뒤에 발생했습니다. 갑자기 이클립스(Oxygen)가 실행이 안되더군요. 

뭐지? 뭐지? 하다가, 이클립스를 다시 설치해보고 실행했더니 처음 한번은 잘 됩니다. 다시 이클립스를 종료했다가 실행시키면 또 안되고 참 희한한 현상이 발생했습니다. ㅠㅠ


아무튼 한참을 해메다가 neon 버전으로 다시 설치해서도 해보고 하다가 java를 실행해봤는데 아래와 같은 에러가 발생하더군요.


Error occurred during initialization of VM

java/lang/NoClassDefFoundError: java/lang/Object


허허, 이런 메시지는 또 처음 봐서 구글링을 해봤더니 jdk, jre 설치가 정상적으로 안된 케이스에서 발생하는 경우가 많은 것 같더군요.


조금 전까지 아무 문제 없던게 도커를 설치했더니 자바가 실행이 안된다? 좀 이해가 안되는 부분이라서 java명령어를 실행할 때 Program Files 하위의 java를 쓰는건지 ProgramData하위의 java를 쓰는건지 확인해보고 싶었습니다. 그때 사용한 명령어는 아래와 같습니다.


 for %i in (java.exe) do @echo. %~$PATH:i


윈도우에서 기본적으로 제공해주는 for 명령어를 이용한 것으로 도움말을 출력해보면 아래와 같습니다.



C:\Users\dev>for /?

파일 집합에서 각 파일에 대해 지정된 명령을 실행합니다.


FOR %변수 IN (집합) DO 명령어 [명령어 매개 변수]


  %변수      바꿀 수 있는 매개 변수를 한 문자로 지정합니다.

  (집합)      하나 이상의 파일을 지정합니다. 와일드카드를 사용할 수 있습니다.

  명령어      각 파일에 대해 수행할 명령을 지정합니다.

  명령어-매개 변수

              지정된 명령의 매개 변수나 스위치를 지정합니다.


일괄 프로그램에서 FOR 명령을 쓰려면, '%변수' 대신 '%%변수'를 지정하십시오.

변수 이름에서는 대문자와 소문자를 구별하므로 %i와 %I는 다릅니다.


명령 확장을 사용하면 FOR 명령에 아래와 같은 추가적인 형태가

지원됩니다.


FOR /D %변수 IN (집합) DO 명령 [명령-매개 변수]


   집합에 대표 문자가 있으면 파일 이름 대신 디렉터리 이름과

   일치하도록 지정합니다.


FOR /R [[드라이브:]경로] %변수 IN (집합) DO 명령 [명령-매개 변수]


   [드라이브:]경로를 루트로 하여 디렉터리 트리를 따라 내려가며

   FOR 구문을 트리의 각 디렉터리에서 실행합니다. /R 스위치 뒤에

   디렉터리가 지정되지 않으면 현재 디렉터리가 사용됩니다.

   집합에 마침표(.)가 사용되면 디렉터리 트리만 나열합니다.


FOR /L %변수 IN (시작,단계,끝) DO 명령 [명령-매개 변수]


   집합은 단계별로 증가/감소하는 시작부터 끝까지의 일련의 숫자입니다.

   따라서 (1,1,5)는 1 2 3 4 5를 나타내며 (5,-1,1)은 5 4 3 2 1을

   나타냅니다.


FOR /F ["옵션"] %변수 IN (파일-집합) DO 명령 [명령-매개 변수]

FOR /F ["옵션"] %변수 IN ("문자열") DO 명령어 [명령-매개 변수]

FOR /F ["옵션"] %변수 IN ('명령어') DO 명령어 [명령-매개 변수]


    또는 usebackq 옵션이 있는 경우:


FOR /F ["옵션"] %변수 IN (파일-집합) DO 명령 [명령-매개 변수]

FOR /F ["옵션"] %변수 IN ('문자열') DO 명령어 [명령-매개 변수]

FOR /F ["옵션"] %변수 IN (`명령어`) DO 명령어 [명령-매개 변수]


   파일-집합은 하나 이상의 파일 이름입니다. 파일-집합의 각 파일은

   다음 파일로 이동하기 전에 열기 또는 읽기 등의 작업이 진행됩니다.

   파일을 읽어서 문자열을 한 행씩 분리하고 각 행을 0개 이상의

   토큰으로 구문 분석하는 과정으로 되어 있습니다. For 루프의 본문은발견된 토큰 문자열에 설정된 변수 값(들)과 함께 호출됩니다.

   기본값으로 /F는 파일의 각 행으로부터 분리된 토큰을 첫 번째 공백에전달합니다. 빈 행은 건너뜁니다. "옵션" 매개 변수를 지정하여

   기본 구문 분석 동작을 무시할 수 있습니다. 이것은 다른 구문 분석

   매개 변수를 지정하는 하나 이상의 키워드를 갖는 인용 부호로

   묶인 문자열입니다.

   키워드는 아래와 같습니다.


   eol=c  - 행 끝 설명 문자를 지정합니다 (하나만)

   skip=n  - 파일의 시작 부분에서 무시할 행의 개수를 지정합니다.

   delims=xxx  - 구분 문자 집합을 지정합니다.  이것은 공백 또


계속하려면 아무 키나 누르십시오 . . .


너무 길어서 짧게 끊었습니다. 위에서 사용한 명령어는 유닉스의 which java와 같이 PATH환경변수에 있는 디렉토리 경로를 훑으면서 제일 처음 만나는 java위치를 출력해줍니다. 즉, 윈도우용 which 명령어라고 생각하시면 될 것 같습니다.



이상입니다.




아래는 기록을 위해서 개인적으로 작성했던 노트입니다.

오픈소스 챗봇 테스트를 위해서 Docker 설치하고 테스트 한 이후부터 이클립스 실행이 안되는 현상 발생
    - 다시 동일한 디렉토리에 Oxygen버전 인스톨러를 이용해서 재설치 한 뒤 launch하면 기동이 되나, 재부팅 후에는 역시 또 안됨
    - Neon 버전처럼 패키지로 배포되는 이클립스는 새로 다운받아서 실행해도 실행 안됨
    - Java를 실행해보니 다음과 같은 에러 메시지 발생
        - Error occurred during initialization of VM
          java/lang/NoClassDefFoundError: java/lang/Object
    - 현재 jdk1.7과 1.8 버전이 설치되어있고 jre역시 7, 8 버전이 설치되어있음
    - 아래 명령어를 이용하여 어느 위치의 자바가 실행되고 있는지 확인
        for %i in (java.exe) do @echo. %~$PATH:i
        - C:\ProgramData\Oracle\Java\javapath\java.exe
    - jdk 1.8을 설치하면 환경변수에 위 경로로 세팅이 됨
    - Docker를 설치하고나서 위 java를 실행하면 에러가 발생함
    - jdk1.7, jdk1.8 의 java.exe를 실행하면 정상적으로  실행이 되는 것을 확인
    - jdk1.8을 재설치하여 정상적으로 java가 실행이 되도록 할 수도 있으나 일단은 환경변수 확인
    - 환경변수에는 JAVA_HOME에 jdk1.8의 패스가 잡혀있고 PATH에 %JAVA_HOME%\bin이 있음, 그리고 ProgramData\OracleJava\javapath도 잡혀있음
    - 환경변수에서 ProgramData\OracleJava\javapath 경로는 제거함
    - 다시 이클립스를 재기동 해보니 정상적으로 기동함

    - jre1.8의 java는 정상적으로 실행이 안됨 -> 재설치






자바 프로그램을 짜다보면 현재 프로젝트의 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.



💻 Programming/Java

JVM 클래스로더란? ( What is ClassLoader ? )

1. 개요
Cass Loader 란 abstrace class로써 Bytecode를 읽어 들여서 class 객체를 생성하는
역활을 담당한다.

Class Loader가 Class를 Loading하는 시점은 ComplieTime이 아닌 Run Time에 Loading이 된다.

프로그래머 가 SampleTest aaa = new SampleTest(); 라는 코드를 처음 실행하면
JVM은 SampleTest라는 Class를 Class Loader를 통해서 SampleTest.clas의 ByteCode를
최초로 메모리에 Load하게 된다. 



2. ClassLoader 기술적 특징
   - Hierarchical 
     Class Loader는 Hierarchical 하게 생성이 가능하고, Parent class laoder에서, child class loader
     갖는것과 같이 Class Loader간의 계층형 구조를 갖게 된다. 최상위 Class Loader는  
     "bootstrap"   Class Loader가 위치 하게 된다.

   - Delegate load request
      Class loading에는 일정한 규칙이 필요하다. 이는 Class Loader가 계측형의 구조를 가지고
      있기 때문에, 어느 시점에 Class 로딩 요청을 받으면 상위 Class Loader가 Loding한 Class가 
      우선권을 가진다. 

   - Have visibility constraint
     Child Class Loader는 Parent Class Loader의 Clss를 찾을수 있지만, 그 반대의 경우는 불가능하다.

   - Cannot unload classes
      Class Loader에 의해서 Loading된 Class들은 unload 될수가 없다.



3. Class Loader 위임
   -

옆의 그림은 class loader delegation model 이다.
     이는 Loading요청을 서로 에게
     전달 하는 ClassLoader의 그래프
     이다. 

     옆의 그림과 같이 Class Loader
     들은 하나의 delegation parent
     함께생성되고 다음 위치 에서
     Class를 찾는다.

     * 다음 위치란
      Cache, Parent, Self

    CalssLoader가 최초 하는 일은
    전에도 같은 Class를 Loading
    하도록 요청을 받았는지를
    먼저 파악한다.

    만약 요청을 받은적이 있으면,
    Cache에 저장된 Class를
    리턴 한다.

    그렇지 않을 경우,
    Parent Class를 Loading 할
    기회를 준다.

    이러한 두 단계들이 반복되고 Depth First 방식으로 탐색이 진행 된다.

    만약 Parent Class에도 해당 Class가 존재하지 않으면 (ClassNotFoundException)
    ClassLoader는 Class의 소스에 대한 공유(작업한 코드)의 경로 (Self)를 검색한다.

    Parent ClassLoader는 Class를 처음으로 loading할 기회가 주어지기 때문에 Root에
    가장 가까운 ClassLoader에 의해 로딩 된다.

   가장 핵심적인 bootstrap class들은 java.lang.Object같은 정확한 클래스 버전이 로딩되었는지
   확인하고, Class Loader가 그 자체 또는 부모(Parent)에 의해서 Loading 되었는지
   Class가 불 수 있도록 한다. 위에서 말했다 싶이 자식에 의해 Loading된 Class 들은 볼 수 없다. 


   - Bootstrap Class Loader
   다른 ClassLoader들과는 달리 Bootstrap Class Loader 는 자바 코드에 의해서
   instance화 될 수 없다
   Bootstrap ClassLoader 는 Boot ClassPath에서 핵심 시스템 Class들을 로딩하는데
   이것은 일반적으로 JavaHome의 jre/lib 디렉토리에 있는 JAR 파일들이다.
   단 -Xbootclasspath 옵션으로 classpath를 추가 수정할 수 있다.


   - Extension Class Loader
   주로 jre/lib/ext 디렉토리에 위치한 Extension 디렉토리에서 Class 들을 Loading 한다. 
   사용자의 classpath를 수정하지 않고 다양한 보안 확장 같은 새로운 확자으로 쉽게
   갈 수 있는 기능을 제공 한다.

   - System Class Loader 
   CLASSPATH 환경 변수에 지정된 결로에서 코드를 로딩 한다. 
   기본적으로 이 Class Loader는 사용자가 생성한 모든 ClassLoader의 Parent 이다. 


  
4. Class Loding 단계 
   - Class Loadig은 Loading, Linking, initialzing 단계로 나누어 진다.

   - 대부분의 Class Loading과 관련된 문제는 이 세단계 중 한 단계에서 발생한다.

   - 로딩 단계는 필요한 Class File을 배치하고 ByteCode로 Loading하는 단계 이다.

   - JVM의 로딩 프로세스는 Class 객체에 매우 기본적인 메모리 구조를 제공한다.
     메소드, 필드, 기타 참조 Class 들이 이 단계에서는 다루어지지 않는다.

 
   - Linking은 세 단계 중에서 가장 복잡한 단계이다. 다름과 같이 세 개의 주요 단계들로 나뉜다. 
     ㄱ. ByteCode 확인 - ByteCode가 정상적으로 작동 하는지 확인 한다. 
     ㄴ. Class Preparation - Class 에서 정의된 필드, 메소드, 인터페잇 들을 나타내는 
                                       데이터 구조를 준비한다. 
     ㄷ. Resolving - Class 에 다양한 방식으로 참조된 모든 Class들을 Loading한다. 
                         - super class, interface, fild, method signature, local fild

   - initialize 단계 동안, Class 내에 포함된 정적 initializer들이 실행된다. 이 단계의 끝에 가서는 
     기본 값으로 초기화 된다. 

   - 이 세 단계를 지나면 Class는 완전히 로딩되고 사용할 준비가 된다. 
     Class Loading은 Lazy방식으로 수행 될 수 있기 때문에 일부 Class Loading Processor 는 
     Loading 시점외에 처음 클래스를 사용할 때 수행될 수도 있다.   


5. Explicit Loading vs Implicit Loading
   - 클래스가 로딩되는 두가지 방식의 차이
   - Explicit : 다음과 같은 메소드 호출들 중 하나를 사용하여 로딩될 때 발생한다.
                  - (java.lang.ClassLoader).loadClass()
                  - Class.forName()
   - 이러한 메소드들 중 하나가 호출 되면 이름이 인자로 지정된 클래스가 클래스 로더에 의해서
     로딩
된다. 
     그렇지 않을 경우, 로더는 클래스를 로딩하기 위해 delegation model을 사용한다.
 
   - Implicit : Class 가 레퍼런스, 인스턴스화, 명시적 메소드 호출을 제외한 상속의 경우 로딩되는 방식
                   경우 슬그머니 로딩작업은 초기화되고 JVM은 필요한 레퍼런스를 결정하여
                   만약 로딩이 되어 있으면 레퍼런스만 리턴되고 그렇지 않을 경우 델리게이션 모델을
                   사용하여 클래스를 로딩하게 된다. 

   


참고 자료:
http://www.ibm.com/developerworks/java/library/j-dclp1/index.html?S_TACT=105AGX02&S_CMP=EDU
및 인터넷 문서



출처 : http://liebus.tistory.com/30



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++;
          }
     }
}

}