반응형

사경인 회계사님이 쓴 재무제표 모르면 주식투자 절대로 하지마라에 나오는 공식인 S-RIM을 계산하여 해당하는 종목을 매주 제공합니다.

 

재무제표 정보를 제공하는 사이트(http://comp.fnguide.com)를 크롤링하여 필요한 정보를 구했습니다.

 

특히, ROE 같은 경우는  당해에 컨센서스가 추측하는 ROE를 기준으로 하였고, 컨센서스가 존재하지 않을 경우 대상에서 제외합니다.

 

목표 수익률은 9%로 하였습니다.

 

당기순이익이 어떠한 이유로 인해(투자, 매각 등) 너무 높아 ROE가 비정상적으로 다른 해보다 높은 기업이 존재합니다.

따라서 아래 종목 리스트는 투자에 참고만 해주시고, 반드시 해당 기업의 재무제표를 다시 확인해주시기 바랍니다.

 

종목명 시가총액 현재가격 매수가격 중간가격 매도가격
NAVER 638163 388500 515345 785285 1655091
기아 331993 81900 92188 101129 129941
POSCO 278998 320000 586431 622395 738278
KB금융 229110 55100 110093 111735 117026
SK텔레콤 219423 304500 369735 381077 417624
신한지주 201990 39100 90243 90792 92560
LG 144560 91900 145887 157257 193893
하나금융지주 133908 44600 110624 112608 119002
HMM 117767 29050 38414 56806 116067
우리금융지주 84455 11600 34449 34963 36618
롯데케미칼 81747 238500 438755 462951 540918
한화솔루션 80337 42000 45545 48102 56344
LG디스플레이 64049 17900 36461 38034 43102
LG유플러스 63090 14450 17650 17873 18591
CJ제일제당 60066 399000 411699 433148 502263
금호석유 54232 178000 280369 383883 717427
미래에셋증권 53557 8430 16560 17095 18818
DB손해보험 46799 66100 94322 97522 107832
한국금융지주 46754 83900 158635 192289 300731
삼성증권 41167 46100 75939 84742 113108
GS 40697 43800 105366 111583 131615
NH투자증권 35317 12550 25109 27484 35139
GS건설 35046 40950 55016 57264 64506
KCC 33546 377500 609006 614478 632112
메리츠증권 32178 4720 8226 9022 11585
키움증권 27662 105500 205726 249087 388808
포스코인터내셔널 27451 22250 28922 30541 35759
대우건설 26932 6480 9101 10465 14861
효성티앤씨 26399 610000 684917 1013803 2073547
한화 26123 34850 71037 77449 98111
효성 22862 108500 146778 171077 249371
영원무역 20295 45800 46188 47554 51958
HDC현대산업개발 17169 26050 47814 50920 60926
DGB금융지주 16898 9990 30958 30964 30984
JB금융지주 16842 8550 21601 22738 26399
동국제강 16414 17200 31570 37066 54773
에스엘 15449 32050 32979 34367 38839
두산 14673 88800 151558 182579 282538
DL 14648 69900 302910 385963 653578
SK가스 13430 145500 229510 236217 257828
대한유화 13260 204000 329954 345334 394890
유니드 11735 132000 154525 189930 304011
LX인터내셔널 11395 29400 50838 59630 87959
GS홈쇼핑 10165 154900 198218 205333 228258
한섬 9704 39400 47777 48151 49356
세아베스틸 9091 25350 52561 55697 65802
풍산 9024 32200 63001 68274 85265
대한해운 8714 2730 3483 3587 3921
동원산업 8367 227500 391141 409778 469830
대상 8177 23600 34515 35741 39693
동원F&B 8143 211000 216865 227235 260651
현대건설기계 7802 39600 69202 70103 73005
SNT모티브 7443 50900 57952 59455 64297
현대두산인프라코어 7372 9270 15386 17380 23807
SK디앤디 6901 31100 31661 35622 48384
코오롱글로벌 6731 26700 32400 40158 65155
국도화학 6316 70100 110750 140779 237540
한국토지신탁 5921 2345 3994 4164 4712
한국자산신탁 5467 4410 7464 8207 10600
매일유업 5451 69500 70638 78158 102390
한라홀딩스 5404 51600 98315 103654 120857
한진 5164 34550 104693 118899 164673
대한제강 4806 19500 34139 42402 69028
금호건설 4396 12000 19918 24662 39950
태영건설 4357 11200 21226 23853 32317
이수화학 4348 15550 18366 24893 45926
원익머트리얼즈 3959 31400 33539 36501 46043
인탑스 3879 22550 33691 36480 45465
웅진씽크빅 3777 3270 3391 3578 4179
한솔제지 3618 15200 27126 27260 27689
화신 3457 9900 10034 11574 16535
계룡건설 3403 38100 86231 98726 138988
동부건설 3285 14450 26456 29723 40249
코리아써키트 3189 13500 15867 16467 18402
한세예스24홀딩스 3180 7950 13136 14789 20112
풍산홀딩스 3014 28950 106661 125239 185104
랩지노믹스 2977 26000 34235 51552 107351
KPX케미칼 2928 60500 115141 116308 120071
유니퀘스트 2632 9630 11776 13494 19030
현대코퍼레이션 2348 17750 26986 28623 33899
하이비젼시스템 2286 15300 15775 19652 32148
한라 2185 5620 12396 14204 20032
도이치모터스 2071 6990 11671 12568 15457
제우스 1952 18800 24325 24724 26012
백산 1861 7690 8453 10319 16331
금화피에스시 1860 31000 46145 47469 51733
디와이파워 1441 13050 22775 25469 34149
SGC이테크건설 1364 67400 141070 181937 313621
엑시콘 1299 12400 18816 23711 39484
현대코퍼레이션홀딩스 1147 12600 22817 24129 28356
코메론 1077 11900 19743 20388 22466
이노인스트루먼트 838 2080 2280 2418 2862
반응형

'주식' 카테고리의 다른 글

[21년 11월 2주차] S-RIM 종목  (0) 2021.11.07
[21년 11월 1주차] S-RIM 종목  (0) 2021.11.01
[21년 10월 5주차] S-RIM 종목  (0) 2021.10.24
[21년 10월 4주차] S-RIM 종목  (0) 2021.10.19
[21년 10월 2주차] S-RIM 종목  (0) 2021.10.02
반응형

객체를 만드는 방법인 생성자(Constructor) 대신 객체를 리턴하도록 하는 public으로 선언된 메서드인 정적 팩터리 메서드를 사용하는 것이 좋은 점이 많다.

 

정적 팩터리 메서드는 다양한 클래스에서 볼 수 있는데, String 클래스의 valueOf 메서드가 그중 하나이다.

    public static String valueOf(Object obj) {
        return (obj == null) ? "null" : obj.toString();
    }

    
    public static String valueOf(char data[]) {
        return new String(data);
    }

 

장점

1. 이름이 있다.

  • 생성자는 이름이 없어 오직 메소드 인자의 시그니처를 보고 파악해야 한다.
  • 정적 팩터리 메서드는 메서드 이름으로 어떤 의미의 객체를 리턴하는지 쉽게 파악할 수 있다.

 

2. 생성자처럼 반드시 새로운 객체를 만들도록 하지 않을 수 있다.

  • 내가 생각하는 가장 큰 장점 중에 하나로, 반드시 새로운 객체를 생성하지 않고, 이미 만들어져 있는 객체를 제공할 수도 있다.
  • 동일한 객체 생성을 요청하는 경우, 이미 만들어 놓은 객체 변수를 리턴할 수 도 있으며 또는 캐시를 사용하여 제공할 수 도 있다.
  • 객체 생성하는데 비용이 클 경우, Immutable 클래스인 경우 사용하기에 좋을 것이다.
    // Boolean code
        public static final Boolean TRUE = new Boolean(true);
        public static final Boolean FALSE = new Boolean(false);
    
        public static Boolean valueOf(boolean b){
            return b ? TRUE : FALSE;
        }

 

3. 생성자처럼 반드시 해당 클래스의 객체를 생성하지 않고, 하위 계층의 클래스를 생성할 수 있다.

  • 생성자는 반드시 자신의 객체만을 리턴한다.
  • 정적 팩터리 메서드는 반환형에 하위 계층 또는 구현체를 리턴할 수 있으므로 더욱 유연하다.
  • java.util.Collections는 다양한 정적 팩터리 메서드가 존재하는데 아래 예제에서는 리턴하는 객체가 Collections에서만 호출 가능한 inner class인 SynchronizedCollection를 생성하여 리턴한다. 이처럼 외부에서는 객체 생성 불가능한 클래스도 정적 메서드 클래스를 통해 리턴할 수 제공할 수 있다.
    package java.util;
    ...
    
    public class Collections {
        ...
    
        public static <T> Collection<T> synchronizedCollection(Collection<T> c) {
            return new SynchronizedCollection<>(c);
        }
    
    
        static class SynchronizedCollection<E> implements Collection<E>, Serializable {
            private static final long serialVersionUID = 3053995032091335093L;
    
            final Collection<E> c;  // Backing Collection
            final Object mutex;     // Object on which to synchronize
    
            SynchronizedCollection(Collection<E> c) {
                this.c = Objects.requireNonNull(c);
                mutex = this;
            }
            
            ...
        }
        
        
        ...
        
    }

 

4. 제네릭을 사용한 객체를 만들 때 편리하다. (JDK  1.7부터는 생성자에서도 지원한다.)

 

단점

1. 정적 팩터리 메서드만 제공하는 클래스라면, 즉 생성자가 private로 되어 있어 생성자를 이용하여 객체를 생성할 수 없다면, 하위 클래스를 만들 수 없다.

 

2. 정적 팩터리 메서드는 일반 메서드와 다른 점이 없으므로 해당 메서드가 정적 팩터리 메서드인지 바로 알 수는 없다. 따라서 문서를 읽어야지 파악 가능하다.

 

 

2번 단점으로 인해, 일반적으로 정적 팩터리 메서드의 네이밍은 아래와 같이 작성한다.

  • valueOf : 주어진 값과 같은 값을 갖는 객체를 반환한다.
        // String.valueOf
        public static String valueOf(Object obj) {
            return (obj == null) ? "null" : obj.toString();
        }​
  • of : valueOf와 동일
        // Optional.of
        public static <T> Optional<T> of(T value) {
            return new Optional<>(value);
        }​
  • getInstance : 일반적으로 이미 존재하는 객체를 반환한다.
    // Singleton example
    public class ExampleClass {
        private static ExampleClass instance = new ExampleClass();
        private ExampleClass() {}
        public static ExampleClass getInstance() {
            return instance;
        }
    }​
  • newInstance : 일반적으로 항상 새로운 객체를 만들어 반환한다.
    // Class.newInstance
    clazz.newInstance()​
  • getType : 특정 클래스에서 Type의 객체를 생성할 경우 사용한다. 일반적으로 이미 존재하는 객체를 반환한다.
  • newType : 특정 클래스에서 Type의 객체를 생성할 경우 사용한다. 일반적으로 항상 새로운 객체를 만들어 반환한다.

 

반응형
반응형

사경인 회계사님이 쓴 재무제표 모르면 주식투자 절대로 하지마라에 나오는 공식인 S-RIM을 계산하여 해당하는 종목을 매주 제공합니다.

 

재무제표 정보를 제공하는 사이트(http://comp.fnguide.com)를 크롤링하여 필요한 정보를 구했습니다.

 

특히, ROE 같은 경우는  당해에 컨센서스가 추측하는 ROE를 기준으로 하였고, 컨센서스가 존재하지 않을 경우 대상에서 제외합니다.

 

목표 수익률은 9%로 하였습니다.

 

당기순이익이 어떠한 이유로 인해(투자, 매각 등) 너무 높아 ROE가 비정상적으로 다른 해보다 높은 기업이 존재합니다.

따라서 아래 종목 리스트는 투자에 참고만 해주시고, 반드시 해당 기업의 재무제표를 다시 확인해주시기 바랍니다.

 

종목명 시가총액 현재가격 매수가격 중간가격 매도가격
NAVER 627486 382000 514847 784429 1653085
기아 317400 78300 92298 101318 130384
POSCO 282485 324000 581401 613758 718018
SK텔레콤 235637 327000 369735 381077 417624
KB금융 229526 55200 110063 111684 116906
신한지주 205090 39700 90169 90665 92262
LG 146290 93000 145457 156518 192159
하나금융지주 137661 45850 110565 112506 118763
HMM 128915 31800 37329 54943 111698
우리금융지주 83727 11500 34440 34947 36581
롯데케미칼 82947 242000 438867 463143 541368
한화솔루션 82154 42950 45649 48281 56764
LG디스플레이 66196 18500 37019 38992 45348
LG유플러스 65710 15050 17650 17873 18591
CJ제일제당 60367 401000 410856 431701 498869
금호석유 54842 180000 280256 383690 716974
미래에셋증권 54002 8500 16529 17042 18695
한국금융지주 47701 85600 157248 189908 295146
DB손해보험 46162 65200 93777 96585 105636
삼성증권 41792 46800 75693 84320 112118
GS 41069 44200 105366 111583 131615
두산밥캣 38997 38900 43909 44021 44384
NH투자증권 35598 12650 25018 27329 34776
GS건설 35559 41550 55130 57460 64967
KCC 35501 399500 609006 614478 632112
메리츠증권 33712 4945 8226 9022 11585
포스코인터내셔널 30042 24350 29024 30718 36173
키움증권 27793 106000 205886 249363 389453
대우건설 27390 6590 9099 10462 14853
효성티앤씨 27221 629000 685354 1014554 2075307
한화 25261 33700 71397 78067 99560
효성 23705 112500 146778 171077 249371
영원무역 19054 43000 46090 47386 51564
HDC현대산업개발 17762 26950 47814 50920 60926
JB금융지주 17138 8700 21568 22681 26266
동국제강 16844 17650 31293 36590 53658
DL 15507 74000 302910 385963 653578
두산 15367 93000 151558 182579 282538
SK가스 14261 154500 228234 234027 252691
대한유화 13943 214500 330890 346941 398660
LX인터내셔널 13411 34600 50040 58260 84744
에스엘 12485 25900 33287 34896 40081
유니드 11690 131500 154525 189930 304011
GS홈쇼핑 10165 154900 198218 205333 228258
한섬 9618 39050 47764 48128 49303
대한해운 9575 3000 3483 3587 3921
풍산 9108 32500 62863 68037 84709
세아베스틸 8876 24750 52827 56153 66873
동원산업 8348 227000 391141 409778 469830
대상 8212 23700 34578 35850 39948
동원F&B 8123 210500 216195 226085 257952
현대건설기계 8008 40650 69334 70328 73533
SNT모티브 7355 50300 58337 60116 65849
현대두산인프라코어 7276 9150 15386 17380 23807
코오롱글로벌 7160 28400 32484 40301 65490
SK디앤디 7012 31600 31661 35622 48384
국도화학 6650 73800 110750 140779 237540
한국토지신탁 6072 2405 3994 4164 4712
한라홀딩스 5676 54200 98691 104300 122372
한국자산신탁 5511 4445 7464 8207 10600
한진 5396 36100 104833 119140 165239
대한제강 5065 20550 34139 42402 69028
이수화학 4921 17600 18366 24893 45926
KG이니시스 4827 17300 17319 20286 29847
금호건설 4598 12550 19316 23629 37526
태영건설 4473 11500 21226 23853 32317
인탑스 4283 24900 33116 35491 43147
원익머트리얼즈 4022 31900 33539 36501 46043
웅진씽크빅 3794 3285 3391 3578 4179
한솔제지 3760 15800 27126 27260 27689
동부건설 3364 14800 26465 29732 40261
계룡건설 3345 37450 86231 98726 138988
한세예스24홀딩스 3264 8160 13136 14789 20112
코리아써키트 3177 13450 15543 15912 17100
랩지노믹스 3149 27500 34235 51552 107351
풍산홀딩스 3144 30200 106661 125239 185104
KPX케미칼 2943 60800 115141 116308 120071
화신 2930 8390 10034 11574 16535
유니퀘스트 2725 9970 11776 13494 19030
현대코퍼레이션 2500 18900 26986 28623 33899
한라 2364 6080 12396 14204 20032
도이치모터스 2115 7140 11671 12568 15457
제우스 2077 20000 24325 24724 26012
백산 1902 7860 8453 10319 16331
금화피에스시 1860 31000 46145 47469 51733
이건산업 1462 13350 19520 21293 27009
디와이파워 1424 12900 22775 25469 34149
SGC이테크건설 1364 67400 141070 181937 313621
엑시콘 1325 12650 18816 23711 39484
현대코퍼레이션홀딩스 1179 12950 22817 24129 28356
코메론 1041 11500 19743 20388 22466
이노인스트루먼트 854 2120 2280 2418 2862
반응형

'주식' 카테고리의 다른 글

[21년 11월 2주차] S-RIM 종목  (0) 2021.11.07
[21년 11월 1주차] S-RIM 종목  (0) 2021.11.01
[21년 10월 5주차] S-RIM 종목  (0) 2021.10.24
[21년 10월 4주차] S-RIM 종목  (0) 2021.10.19
[21년 10월 3주차] S-RIM 종목  (0) 2021.10.10
반응형

Hex2Bytes

1. BigInteger(String val, int radix)

	public static void main(String args[]) {
		String hex = "aaaaaa";
		byte[] bytes = new BigInteger(hex, 16).toByteArray();
	}

 

2. 순수 자바

	public static byte[] hexStringToByteArray(String s) {
		int len = s.length();
		byte[] data = new byte[len / 2];
		for (int i = 0; i < len; i += 2) {
			data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
			        + Character.digit(s.charAt(i + 1), 16));
		}
		return data;
	}

 

3. javax.xml.bind.DatatypeConverter.parseHexBinary(String lexicalXSDHexBinary)

 

4. org.apache.commons.codec.binary.Hex.decodeHex(char[] data)

성능 비교

BigInteger는 10^7부터는 너무 오래걸려서 테스트 불가능했다.

 

 

차트에는 BigInteger의 10^6데이터는 표현하지 않았다.

 

 

- BigInterger가 성능이 제일 좋지 않은것으로 판단된다. BigInteger라도 너무 큰 숫자를 처리하기에는 성능 이슈가 있는것으로 판단된다.

 

- DatatypeConverter.parseHexBinary는 작은 데이터도 평균적으로 0.15초는 적어도 소요되었다. 신기해서 소스를 보니, 아래 소스처럼 처음 수행될 때 실제 컨버터 구현체를 인스턴스화 한다. 만약 실시간성이 중요하다면, 미리 인스턴스화 하는게 좋을 것 같다. 

    public static java.math.BigInteger parseInteger( String lexicalXSDInteger ) {
        if (theConverter == null) initConverter();
        return theConverter.parseInteger( lexicalXSDInteger );
    }
    
    private static synchronized void initConverter() {
        theConverter = new DatatypeConverterImpl();
    }

 

- DatatypeConverter 초기화 시간만 제외한다면 BigInteger를 제외한 세 개는 거의 동일한 성능을 보인다.

 

- DatatypeConverter 또는 Hex를 기본적으로 어플리케이션에서 사용하지 않는다면, 순수자바로 구현된 hexStringToByteArray를 사용하는 것이 좋다고 생각된다.

반응형
반응형

이슈

카프카가 Failed to clean up log for __consumer_offsets 에러를 발생시키고, 몇 분 뒤에 Shutdown broker because all log dirs in 에러를 남기고 비정상 종료되는 현상이다.

 

공식 이슈

https://issues.apache.org/jira/browse/KAFKA-6188

 

[KAFKA-6188] Broker fails with FATAL Shutdown - log dirs have failed - ASF JIRA

Just started with version 1.0.0 after a 4-5 months of using 0.10.2.1. The test environment is very simple, with only one producer and one consumer. Initially, everything started fine, stand alone tests worked as expected. However, running my code, Kafka cl

issues.apache.org

https://github.com/apache/kafka/pull/6403

 

KAFKA-6188; Fix windows clean log fail caused shut down by theidexisted · Pull Request #6403 · apache/kafka

During debugging, I find that delete or rename a file before close it is illegal on windows, so I changed the function deleteSegment to add a direct close handle operation. I have manually test it ...

github.com

 

공식 이슈로 올라온 것은 2017년 11월 버전 1.0.1이고, 2018년 8월 버전 2.0부터는 패치되었다고 한다.

하지만 21년 6월 버전 2.6까지도 계속 발생하는 것으로 봐서는 아직까지 해결되지 않은 것으로 판단된다.

 

 

원인

카프카는 data를 retention 주기만큼 보관하고 있다가 이후 삭제한다. 이때 Cleaner가 동작하게 되는데, 삭제해야 하는 데이터의 로그 파일이 존재하지 않을 경우 위와 같은 에러가 발생한다.

 

처음 이슈가 발생했을 때 Windows에서만 발생하는 이슈라고 하였지만, 현재는 여러 OS에서 발생하고 있다.

 

어떤 개발자가 말하기로는, 카프카의 데이터 로깅 위치(log.dirs)를 변경할 경우 발생한다고 한다. 하지만 디폴트 설정으로 사용한 개발자도 해당 이슈가 발생한다고 한다.

 

아직 까지 정확한 원인과 이슈 해결이 되지 않았다.

 

 

 

해결

많은 사람들이 가장 많이 해결한 방법으로는 kafka의 data 경로에 모든 파일을 삭제하면 된다.

server.properties 파일에 아래 설정 경로에 있는 데이터를 모두 삭제하면 된다. (카프카 토픽에 저장했던 데이터들이 모두 삭제된다.)

log.dirs=/home/kafka/kafka/logs

 

하지만 이렇게 해도 되지 않을 경우, 다음으로는 주키퍼의 data 파일을 삭제한다.

zookeeper.properties 파일에 아래 설정 경로에 있는 데이터를 모두 삭제하면 된다. (카프카 토픽 자체가 모두 삭제된다.)

dataDir=/home/kafka/kafka/zookeeper

 

이렇게 해도 되지 않을 경우, 재설치를 추천한다.

반응형

'서버 > Kafka' 카테고리의 다른 글

[KAFKA] Consumer 메시지 중복 처리  (0) 2021.12.06
반응형

Grafana는 시계열 데이터에 대한 대시보드를 제공해주는 Data Visualization Tool이다.

 

Grafana 설치

wget https://dl.grafana.com/oss/release/grafana-7.3.7-1.x86_64.rpm
sudo yum install grafana-7.3.7-1.x86_64.rpm

 

 

Grafana 실행

  • 버전 및 운영제에 따라 실행방법은 https://grafana.com/docs/grafana/latest/installation/ 참고
  • Red Hat, CentOS, RHEL, and Fedora(64 Bit), v7.3.7으로 설명
  • OS버전에 따라 systemctl 명령어가 다를 수 있음.
    • ex) CentOS 6 ⇒ sudo service grafana-server start
# 데몬 리로드
sudo systemctl daemon-reload

# 실행
sudo systemctl start grafana-server

# 확인
sudo systemctl status grafana-server

 

Grafana 로그인

Grafana Data Source 설정

  • 정보를 수집할 Data Source를 설정한다.
  • 대시보드 첫 화면에서 ‘Add your first data source’를 클릭 또는 왼쪽에 톱니바퀴(Configuration)을 누르면 나타나는 ‘Data sources’를 클릭하여 등록할 수 있다.
반응형

'서버' 카테고리의 다른 글

프록시 서버 (포워드 프록시, 리버스 프록시)  (0) 2021.08.20
반응형

자바의 가상 머신은 두 가지 종류의 이벤트를 받아 프로그램을 종료한다.

  1. 프로그램이 정상적으로 종료되거나 System.exit()
  2. 사용자 인터럽트(Ctrl+C)나 사용자 로그오프 또는 시스템 종료와 같은 시스템 전체 이벤트에 대한 응답 이벤트

 

프로그램이 정상 또는 비정상 종료하기 전에 특정 작업을 수행할 수 있도록 자바는 java.lang.Runtime.addShutdownHook(Thread t)을 제공한다. 종료될 때 수행할 내용을 정의한 Thread를 인자로 전달한다.

 

기본 예제

아래 결과는 “End”가 출력된 후, “Hook Run” 이 출력된다.

public class ShutdownHookTest {

	static class HookThread extends Thread {
		@Override
		public void run() {
			System.out.println("Hook Run");
		}
	}

	public static void main(String[] args) {
		Runtime.getRuntime().addShutdownHook(new HookThread());

		System.out.println("End");
	}
}

 

아래처럼 비정상 동작으로 프로그램이 종료되어 “End”는 출력되지 않지만 “Hook Run”이 출력된다.

public class ShutdownHookTest {

	static class HookThread extends Thread {
		@Override
		public void run() {
			System.out.println("Hook Run");
		}
	}

	public static void main(String[] args) {
		Runtime.getRuntime().addShutdownHook(new HookThread());

		int errorNum = 1 / 0;
		System.out.println("End");
	}
}

 

콘솔에서 sleep 동안 인터럽트(Ctrl+C)를 줄 경우에도 “End”는 출력되지 않지만 “Hook Run”이 출력된다.

public class ShutdownHookTest {

	static class HookThread extends Thread {
		@Override
		public void run() {
			System.out.println("Hook Run");
		}
	}

	public static void main(String[] args) {
		Runtime.getRuntime().addShutdownHook(new HookThread());

		try {
			System.out.println("sleep 3s");
			Thread.sleep(3000);
		} catch (Exception e) {
			e.printStackTrace();
		}
        
		System.out.println("End");
	}
}

 

순서 지정 불가능

Shutdown Hook은 실행되는 순서를 결정할 수 없다. 즉 addShutdownHook() 메소드끼리의 호출 순서에 상관없이 동시에 실행된다. 아래처럼 HookThread를 먼저 등록하고, HookThread2를 등록하였지만 실행할 때마다 출력되는 순서는 랜덤 하다.

public class ShutdownHookTest {

	static class HookThread extends Thread {
		@Override
		public void run() {
			System.out.println("Hook Run1");
		}
	}

	static class HookThread2 extends Thread {
		@Override
		public void run() {
			System.out.println("Hook Run2");
		}
	}

	public static void main(String[] args) {
		Runtime.getRuntime().addShutdownHook(new HookThread());
		Runtime.getRuntime().addShutdownHook(new HookThread2());

		System.out.println("End");
	}
}

 

Hook의 실행 막기

Runtime.halt(int)를 사용하면 등록된 Shutdown Hook을 실행하지 않고 종료된다. 만약 종료 중에 Halt가 호출될 경우 (종료 중이라면 등록된 Shutdown Hook 쓰레드들이 동시에 실행되는 상태) 실행 중인 Hook이 마칠 때까지 대기하지 않고, 바로 종료한다. 아래 예제를 보면 종료되기 전에 halt() 메소드를 호출하였으므로 등록된 Hook이 실행되지 않는다.

	// ...
	
	public static void main(String[] args) {
		Runtime.getRuntime().addShutdownHook(new HookThread());
		Runtime.getRuntime().addShutdownHook(new HookThread2());

		System.out.println("End");
		Runtime.getRuntime().halt(0);
	}
}

 

Hook 발생 중 Hook 제어 불가능

Shutdown Hook이 시작되면 Hook을 추가할 수도 제거할 수 없다. 시도할 경우 IllegalStateException 예외가 발생한다. 아래 예제는 예외가 발생하는 경우이다. Shutdown Hook에 추가한 Hook Thread에 새로운 Hook을 추가하였다. 따라서 종료되면서 IllegalStateException 예외가 발생한다.

public class ShutdownHookTest {

	static class HookThread extends Thread {
		@Override
		public void run() {
			Runtime.getRuntime().addShutdownHook(new HookThread());
			System.out.println("Hook Run1");
		}
	}
	
	// ...

}

 

이외 유의사항

쓰레드는 언제나 어렵다. 복잡하고 디버깅하기도 힘들다. Shutdown Hook도 마찬가지로 쓰레드를 사용하므로 제대로 구현하지 않는다면 원하는 대로 작동하지 않을 수 있다.

 

프로그램이 종료될 때 모든 쓰레드 Hook이 동시에 실행되며 이외에 쓰레드들도 실행 중일 것이다. 따라서 thread-safe 하게 작성하여 데드락을 피해야 한다.

 

뿐만 아니라, 무조건 실행된다는 보장이 없으므로 Shutdown Hook 메소드를 100% 신뢰하지는 않는 것이 좋다. 정말 중요한 작업이라면 명시적인 종료자 메소드를 구현하여 사용하는 게 안전할 것이다.

 

마지막으로 Hook 쓰레드에서 많은 시간을 소모하면 안 된다. 만약 시스템을 종료하는 상황이라면 시스템이 종료되면 JVM이 종료되면서 Hook이 실행되겠지만 시간이 오래 걸릴 경우, 시스템은 무시하고 강제로 종료돼버린다.

반응형
반응형

멀티쓰레드 프로그래밍에서 쓰레드들이 모든 작업을 마친 후에 특정한 작업을 해야하는 경우가 있다. 이를 위해 다른 쓰레드들에서 일련의 작업이 완료 될 때까지 대기하도록 Sync를 맞춰주는 기능을 자바는 java.util.concurrent.CountDownLatch(int count)을 제공한다.

 

CountDownLatch를 인스턴스화할 때 주어진 카운트로 초기화된다. await 메서드를 실행하면 해당 쓰레드는 다른 쓰레드에서 countDown 메서드 호출로 인해 현재 카운트가 0이 될 때까지 대기한다. 그 후에는 대기중인 스레드가 해제된다.

 

  1. Main 쓰레드는 latch.await() 메소드에 의해 대기상태로 진입한다.
  2. 이 후 Worker 쓰레드들이 자신의 작업을 마친 후, latch.countDown() 메소드를 통해 카운트를 줄여간다.
  3. 카운트가 0이 되면 Main 쓰레드를 대기상태에서 해제된다.
public class CountDownLatchExample {
	static final int max = 3;

	public static void testCountDownLatch() throws Exception {
		final CountDownLatch latch = new CountDownLatch(max);

		for (long i = 1; i <= max; i++) {
			new Thread(new Worker(latch, i * 100)).start();
		}

		latch.await();

		System.out.println("########### CountDownLatch End ###########");
	}

	static class Worker implements Runnable {
		private CountDownLatch latch;
		private long n;

		public Worker(CountDownLatch latch, long n) {
			this.latch = latch;
			this.n = n;
		}

		@Override
		public void run() {
			try {
				int cnt = 0;
				for (int i = 0; i < n; i++) {
					cnt++;
				}

				System.out.println(cnt);
			} catch (Exception ex) {
				ex.printStackTrace();
			} finally {
				if (this.latch == null) {
					return;
				}

				latch.countDown();
			}
		}
	}

	public static void main(String[] args) throws Exception {
		System.out.println("start");
		testCountDownLatch();
		System.out.println("end");
	}

	/**
	 * start
	 * 200
	 * 100
	 * 300
	 * ########### CountDownLatch End ###########
	 * end
	 */
}
반응형

+ Recent posts