백준 1904 : 문제링크

  • 문제유형 :

    • 동적 프로그래밍
  • 설명

    • 동적 프로그래밍 문제를 풀기 위해서는 점화식(인접한 항들 사이의 관계식)을 세워야 한다.

      스크린샷 2020-10-30 오후 7 19 58

    • D[i] = 수열의 길이가 i일 때의 경우에 수

    • D[i] = D[i-1] + D[i-2]

  • 풀이

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    n = int(input())

    dp = [0] * 1000001
    dp[1] = 1
    dp[2] = 2

    for i in range(3, n+1)
    dp[i] = (dp[i - 2] + dp[i - 1]) % 15746

    print(d[[n]])

Comment and share

정규표현식 (Regular Expression)

정규표현식

  • 특정 조건에 맞는 문자열을 검색/치환하는 패턴 기반의 식
  • 이메일, 전화번호 등 특정한 형식에 맞는지 validation하는 데에 사용

정규표현식 표현 방법

  • 정규 표현식의 기본 작성 방식

    1
    "/패턴/[플래그(Opt.)]"
  • 기본 메타 문자

    메타 문자 의미
    ^x x로 시작
    x$ x로 끝
    .x x앞에 하나의 문자가 있음
    x+ x가 1번 이상 반복
    x? x가 있거나 없음
    x* x가 0번 이상 반복
    `x y`
  • 괄호의 활용

    regexp 의미
    (xy) 괄호 안의 내용을 그룹화
    x{n} n번 반복됨
    x{n,} n번 이상 반복됨
    x{n, m} n번 이상, m번 이하 반복됨
    [xy] x 또는 y
    [a-z] 알파벳 소문자 (a~z)
    [0-9] 숫자
    [가-힣] 한글
    [^x] x가 아닌 것
    [^0-9] 숫자가 아닌 것
  • \ 축약 문자

    regexp 의미
    \^, \., … \ 뒤에 나오는 문자를 문자로 처리
    \b 단어의 경계를 찾는다.
    \B 단어의 경계가 아닌 것을 찾는다.
    \d 숫자를 찾는다.
    \D 숫자가 아닌 것을 찾는다.
    \s 공백 문자를 찾는다.
    \S 공백 문자가 아닌 것을 찾는다.
    \w [a-zA-Z0-9_]
    \W [^a-zA-Z0-9_]

    JAVA에서는 \\\ 처럼 입력해야 \\처럼 동작한다

  • 유용한 정규식 예

    • 한글 이름 : ^[가-힣]{2,5}$
    • 핸드폰 번호: ^01(0|1|2|6|9)[-\s]?\d{3,4}[-\s]?\d{4}$
    • 이메일 주소: ^[\w\.-]{1,64}@[\w\.-]{1,252}\.\w{2,4}$

Flag

Flag 기능
g 문자열 내 모든 패턴을 찾음
i 대소문자를 구분하지 않음
m 문자열의 모든 줄에서 찾음

정규표현식을 사용하는 클래스

Pattern 클래스

  • 정규식의 컴파일된 표현 입니다(정규식을 적용 가능하도록 컴파일해서 가지고 있습니다).

  • Pattern 클래스는 공개된 생성자를 제공하지 않습니다.

  • 패턴을 생성하려면 Pattern객체를 반환하는 정적 compile 메소드를 호출해야 합니다.

  • 이 메소드는 첫 번째 인자로 정규식 문자열을 받아 들입니다.

    메소드 설명
    public static Pattern compile(String regex) Pattern 객체를 생성
    public Matcher matcher(CharSequence input) 입력을 분석하는 Matcher 객체 생성
    public static boolean matches(String regex, CharSequence input) 입력이 regexp에 해당하는지 판단

Matcher 클래스

  • 패턴을 해석하고 입력 문자열에 대해 일치 작업을 수행하는 엔진입니다.

  • Pattern 클래스와 마찬가지로 Matcher는 어떤 공개된 생성자도 정의하고 있지 않습니다.

  • Matcher객체는 Pattern 객체의 matcher 메소드를 호출해서 얻습니다.

    메소드 설명
    find() 정규표현식에 부합되는 내용이 문자열에 포함되어 있는지 반환. 이전 검색 위치부터 이어서 검색.
    start() 패턴에 부합되는 요소의 시작 인덱스 반환
    end() 패턴에 부합되는 요소가 끝나는 위치 + 1을 반환
    matches() 문자열 전체가 정규표현식에 일치하는지 반환
    lookingAt() 비교하려는 문자열이 정규표현식으로 시작하는지 반환. 0번 인덱스부터 검색.
    replaceFirst() 일치하는 첫 패턴을 문자열로 대체
    replaceAll() 일치하는 모든 패턴을 문자열로 대체
    reset() Matcher의 정보를 리셋하여 0번 인덱스부터 다시 검색

정규식 캡쳐 그룹

  • 정규표현식에서 캡쳐링 그룹은 괄호로 둘러싼 영역이다.

  • 사용 예

    • 순서로 그룹 가져오기

      1
      2
      3
      4
      5
      6
      7
      8
      9
      Pattern pattern2 = Pattern.compile("^\\w+):(\\w+)\\.(\\w+)$");
      Matcher matcher2 = pattern2.matcher("filename:temp.png");

      matcher2.find();
      System.out.println(matcher2.group()); // 매칭된 전체가 출력
      System.out.println(matcher2.group(0)); // 매칭된 전체가 출력
      System.out.println(matcher2.group(1)); // 첫번째 그룹
      System.out.println(matcher2.group(2));
      System.out.println(matcher2.group(3));
    • Name으로 그룹 가져오기

      1
      2
      3
      4
      5
      6
      7
      8
       Pattern pattern2 = Pattern.compile("^(?<field>\\w+):(?<name>\\w+)\\.(?<ext>\\w+)$");
      Matcher matcher2 = pattern2.matcher("filename:temp.png");

      matcher2.find();

      System.out.println(matcher2.group("field")); // name group
      System.out.println(matcher2.group("name"));
      System.out.println(matcher2.group("ext"));

Comment and share

DATABASE-Crontab

Crontab

  • 유닉스 OS 계열에서 특정 시간에 특정 작업을 해야하는 경우 사용하는 스케쥴러입니다.

  • crontab basic

    • 스케쥴 설정

      아래의 커멘드를 입력하면 스케줄을 설정할수 있는 vi 에디터 페이지가 생성된다. 여기에 어떤 주기로 어떤 파일을 실행할지에 대한 리스트를 작성해주면 된다.

      1
      $ crontab -e
    • 스케쥴 리스트 확인

      현재 crontab의 스케쥴을 확인할 수 있다.

      1
      $ crontab -l
  • 주기 설정

    1
    2
    3
    4
    5
    vi time.py

    import datetime
    today = datetime.datetime.now()
    print(str(today))
    • crontab -e 설정

    • * * * * * ->
      분(0-59) | 시간(0-23) | 일(1-31) | 월(1-12) | 요일(0-7)

      • 요일에서 0과 7은 일요일

      • 2분 간격으로 실행

        1
        */2 * * * * python3 /home/ubuntu/time.py >> time.txt
      • 매시 10분에 실행

        1
        10 * * * * python3 /home/ubuntu/time.py >> time.txt
      • 매시 10분과 20분에 실행

        1
        10,20 * * * * python3 /home/ubuntu/time.py >> time.txt
      • 매일 5시 10분과 20분에 실행

        1
        10,20 5 * * * python3 /home/ubuntu/time.py >> time.txt
      • 일요일 5시 10분과 20분에 실행

        1
        10,20 5 * * 0 python3 /home/ubuntu/time.py >> time.txt
      • 5시에서 10시까지 매시에 5분마다 time.py를 실행하고 결과를 time.txt에 저장

        1
        */5 5-10 * * 0 python3 /home/ubuntu/time.py >> time.txt
  • time zone 변경

    타임존 변경

    • 현재 사용 시간 확인

      $ timedatectl

    • 사용하는 파일 심볼릭 링크확인

      $ ls -l /etc/localtime

    • 사용 할수 있는 타임존 확인

      $ timedatectl list-timezones | grep Asia

    • 타임존 변경

      $ sudo timedatectl set-timezone Asia/Seoul

    • 심볼릭 링크 수정

      $ sudo unlink /etc/localtime

      $ sudo ln -s /usr/share/zoneinfo/Asia/Seoul /etc/localtime

  • vim 에디터 인코딩 변경

    $ vi .vimrc

    set encoding=utf-8

  • crontab 로그 확인

    아래의 명령으로 crontab의 시스템 로그를 확인 할수 있습니다.

    $ grep CRON /var/log/syslog

  • crontab 에러 확인 및 해결

    에러가 발생하면 아래와 같은 에러 로그를 확인할수 있습니다.

    Mar 4 07:42:01 ip-172-31-3-64 CRON[7494]: (CRON) info (No MTA installed,
    discarding output)

- MTA : Mail Transfer Agent
- 에러 메시지 확인하는 방법 1
    - $ sudo apt-get install postfix
    - $ cat /var/mail/ubuntu
- 에러 메시지 확인하는 방법 2
    - $ sudo apt install mailutils
    - $ mail
- crontab에서 실행되는 python 환경

    - crontab 에서는 .bash_profile이 실행되지 않기때문에 pyenv 환경이 적용되지 않습니다.

        <!--hexoPostRenderEscape:<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">vi version.py</span><br><span class="line"></span><br><span class="line">import sys</span><br><span class="line">print(sys.version.split(&quot; &quot;)[0])</span><br></pre></td></tr></table></figure>:hexoPostRenderEscape-->

        <!--hexoPostRenderEscape:<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">crontab -e</span><br><span class="line"></span><br><span class="line">\* \* \* \* \* python /home/ubuntu/version.py &gt;&gt; version.txt</span><br></pre></td></tr></table></figure>:hexoPostRenderEscape-->

- pyenv 환경에 있는 python으로 실행

    -  직접 python 경로 입력

       \* \* \* \* \* /home/ubuntu/.pyenv/versions/python3/bin/python /home/ubuntu/version.py >> version.txt

    - PATH 설정

      PATH=/usr/local/bin/:/sbin:/bin:/usr/sbin:/home/ubuntu/.pyenv/versions/python3/bin

      \* \* \* \* \* python /home/ubuntu/version.py >> version.txt

Comment and share

MongoDB

MongoDB Setting

  1. MongoDB 설치 및 설정

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    sudo apt update -y
    sudo apt upgrade -y
    sudo apt install -y mongodb
    sudo systemctl status mongodb
    sudo vi /etc/mongodb.conf
    # bind_ip = 0.0.0.0
    # auth = true
    # 패스워드 설정
    $ mongo
    > use admin
    > db.createUser({ user: "rada", pwd: "radapw", roles: [ "root" ] })
    > quit()
    $ sudo systemctl restart mongodb
    # aws 인스턴스 27017 포트 접속 허용

    mongo 명령어를 입력하면 mongo shell에 접속됩니다.

  2. Install Robomongo

    https://robomongo.org/ 페이지에서 경로에서 ROBO 3T 다운로드 후 설치 합니다.

  3. Connection

    MongoDB Connections에서 ip를 입력하여 서버의 mongoDB에 접속합니다.


문법

ref : https://docs.mongodb.com/v3.6/reference/

  • Create Database

    • mongo 라는 이름의 데이터 베이스 생성

      1
      use mongo
    • 현재 사용중인 데이터 베이스 확인

      1
      db
    • database list 확인

      1
      show dbs
      • 데이터 베에스를 생성후에 최소 1개이상의 document를 추가해야 생성된 데이터 베이스가 보인다
- document 생성
    <!--hexoPostRenderEscape:<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">use</span> mongo</span><br><span class="line">db.user.insert(&#123;<span class="string">&quot;name&quot;</span>:<span class="string">&quot;alice&quot;</span>, <span class="string">&quot;age&quot;</span>:<span class="number">20</span>, <span class="string">&quot;email&quot;</span>:<span class="string">&quot;alice@gmail.com&quot;</span>&#125;)</span><br></pre></td></tr></table></figure>:hexoPostRenderEscape-->
  • Delete Database

    • 현재 사용중인 데이터 베이스 삭제
      1
      db.dropDatabase()
  • Create Collection

    refer https://docs.mongodb.com/v3.6/reference/method/db.createCollection/

    • syntax

      1
      db.createCollection(collection 이름, [option])
    • option

      • capped : true로 설정하면 collection의 최대 용량을 설정 (최대 용량의 크기는 size 옵션으로 설정), 설정된 최대용량 이상으로 데이터가 입력되면 오래된 데이터 부터 자동으로 삭제됩니다.
      • autoIndex : true로 설정하면 _id 필드에 index가 자동으로 생성됩니다.
      • size : 숫자 데이터를 사용하며 collection의 최대 사이즈를 byte 단위로 지정
      • max : 숫자 데이터를 사용하며 최대 document 갯수를 설정
    • user 컬렉션을 생성

      1
      db.createCollection("user")
    • autoIndex와 max 옵션을 설정하여 info 컬렉션을 생성

      1
      2
      db.createCollection("info1", { autoIndexId: true, capped: true, size: 500, max:5 })
      db.createCollection("info2", { autoIndexId: true, capped: true, size: 50, max:5 })
    • createCollection을 사용하지 않고 article 컬렉션을 생성

      1
      db.articles.insert( {"title":"data science", "contents":"mongodb" } )
    • 컬렉션 리스트 확인

      1
      show collections
  • Delete Collection

    • articles 컬렉션 삭제
      1
      db.articles.drop()
  • Make Document

    • syntax

      1
      db.<collection_name>.insert(<document>)
    • info 컬렉션에 document 추가

      1
      2
      3
      db.info1.insert({ "subject":"python", "level":3 })
      db.info1.insert({ "subject":"web", "level":1 })
      db.info1.insert({ "subject":"sql", "level":2 })
    • 한번에 여러개의 document 추가

      • max:5 옵션 제한에 걸려 5개의 데이터가 info1에 들어간다.

        1
        2
        3
        4
        5
        6
        7
        8
        db.info1.insert( [
        { "subject":"python", "level":3 },
        { "subject":"web", "level":1 },
        { "subject":"sql", "level":2 },
        { "subject":"python", "level":3 },
        { "subject":"web", "level":1 },
        { "subject":"sql", "level":2 },
        ])
      • size:50 옵션 제한에 걸려 4개의 데이터가 info2에 입력된다.

        1
        2
        3
        4
        5
        6
        7
        db.info2.insert( [
        { "subject":"python", "level":3 },
        { "subject":"web", "level":1 },
        { "subject":"sql", "level":2 },
        { "subject":"python", "level":3 },
        { "subject":"web", "level":1 },
        ])
      • info collection 생성하면서 document 추가

        1
        2
        3
        4
        5
        6
        7
        8
        db.info.insert( [
        { "subject":"python", "level":3 },
        { "subject":"web", "level":1 },
        { "subject":"sql", "level":2 },
        { "subject":"java", "level":3 },
        { "subject":"html", "level":1 },
        { "subject":"css", "level":2 },
        ])
  • Delete Document

    • level2인 데이터 삭제 : 제약조건이 걸려있는 컬렉션의 도큐먼트는 삭제가 안됩니다.
      1
      db.info.remove( {level:2} )
  • Find

    ref : https://docs.mongodb.com/manual/reference/method/db.collection.find/index.html

    • syntax

      1
      db.collection.find(query, projection)

      query : document 조회 조건을 설정. 모든 document를 조회 할때는 ({})를 사용

      projection : document를 조회할때 보여지는 필드(컬럼)를 정의

    • query

      • 기본 document 조회

        • info 컬렉션에 있는 모든 document 조회

          1
          2
          db.info.find()
          db.getCollection('info').find({})
        • subject가 python인 document 조회

          1
          db.info.find({"subject": "python"})
      • 비교 연산자

        ref : https://docs.mongodb.com/v3.6/reference/operator/query/

        • level이 2 이하인 document를 조회

          1
          db.info.find({"level": {$lte: 2} })
        • level이 3 이상인 document를 조회

          1
          db.info.find({"level": {$gte: 3} })
        • subject가 java와 python을 포함하는 document 조회

          1
          db.info.find( {"subject": {$in: ["java", "python"]}} )
      • 논리 연산자

        1. $or : 조건중 하나라도 true이면 true
        2. $and : 모든 조건이 true이면 true
        3. $not : 조건중 하나라도 false이면 true
        4. $nor : 모든 조건이 false이면 true (or와 반대 개념)
        • subject가 python이고 level이 3이상인 document 조회

          1
          db.info.find({ $and: [ { "subject":"python" }, { "level": {$gte: 3} } ] })
        • subject가 python이아니고 level이 1이하가 아닌 document 조회

          1
          db.info.find({ $nor: [ { "subject":"python" }, { "level": {$lte: 1} } ] })
        • level이 2보다 크지 않은 document 조회 (2 포함)

          1
          db.info.find({ "level": { $not: {$gt: 2} } })
      • $where

        • $where 연산자를 사용하면 자바스크립트 표현식 사용이 가능합니다.

        • level이 1인 document 조회

          1
          db.info.find( { $where: "this.level == 1"} )
    • projection

      document를 조회할때 보여지는 필드(컬럼)를 정의합니다.

      • Basic

      • subject와 comments만 출력되도록 find

        • 설정을 true 값을 설정하던가 false 값을 설정합니다. ( _id는 따로 설정을 안하면 true )
          1
          2
          3
          db.info.find({},{"_id":false, "level":false})
          db.info.find({},{"subject":true, "level":true})
          db.info.find({},{"_id":false, "subject":true, "level":true})
  • Find Method

    find method를 사용하면 find를 사용한 document의 결과를 가공하여 출력할수 있습니다.

    • sort

      • document를 정렬시켜 줍니다.
      • ‘sort({key: value})’ 와 같은 포멧으로 사용을 하며 key는 정렬할 필드명을 작성하고, value는 오름차순은 1, 내림차순을 -1을 넣어주면 됩니다.
    • info 컬렉션의 document를 level 오름차순으로 정렬

      1
      db.info.find().sort({"level":1})
    • info 컬렉션의 document를 level 내림차순으로 정렬

      1
      db.info.find().sort({"level":-1})
    • level을 기준으로 내림차순으로 정렬한 후 subject를 기준으로 오름차순으로 정렬

      1
      db.info.find().sort({"level":-1, "subject":1})
    • limit

      • limit을 사용하면 document출력 결과의 수룰 제한할수 있습니다.

      • document의 결과를 3개 까지만 출력

        1
        db.info.find().limit(3)
      • document의 결과를 level로 내림차순으로 정렬하고 3개까지만 출력

        1
        db.info.find().sort({"level":-1}).limit(3)
    • skip

      skip을 검색한 document의 결과의 시작부분을 설정할때 사용합니다.

      • document를 3번째 부터 출력

        1
        db.info.find().skip(2)

        limit, skip을 함께 사용해서 mysql의 limit과 같이 사용할수 있습니다.

  • update

    ref : https://docs.mongodb.com/manual/reference/command/update/index.html

    • syntax

      1
      db.collection.update( query, update, { upsert: <bool>, multi: <bool> })
      • upsert : insert와 update의 합성어 (데이터가 있으면 update, 없으면 insert 한다는 의미)

      • multi : true로 설정되면 여려개의 document를 수정합니다. 기본값은 false

    • 특정 document를 새로운 document로 수정하기

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      db.info.update(
      { "subject": "html" },
      { "subject": "sass", "level":2}
      )

      db.info.update(
      { "subject": "less" },
      { "subject": "less", "level": 2},
      { "upsert": true}
      )
  • $set, $unset

    • $set을 사용하면 특정 document의 필드를 수정할수 있습니다.

    • $unset를 사용하면 특정 document의 필드 제거할수 있습니다.

    • python의 level을 3으로 수정 (한개의 데이터만 수정)

      1
      db.info.update( { subject: "java" }, { $set: { level: 4 } } )
    • level 2를 level 1로 수정 (여러개의 데이터 수정)

      1
      2
      3
      4
      5
      db.info.update(
      { level: 2 },
      { $set: { level: 1 } },
      { multi: true }
      )
    • subject가 sass인 document의 level필드 삭제

      1
      2
      3
      4
      db.info.update(
      { subject: "sass" },
      { $unset: {level: 1} }
      )

      level: 1의 1은 true를 의미합니다.

    • level이 2이하인 데이터를 1로 수정하기

      1
      2
      3
      4
      5
      db.info.update(
      { level: {$lte: 2} },
      { $set: {level: 1} },
      { multi: 1 }
      )
    • level이 없는 데이터 level 추가하기

      1
      2
      3
      4
      5
      db.info.update(
      { level: {$exists: false} },
      { $set: {level: 2} },
      { multi: 1 }
      )
  • Function

    자바스크립트 문법으로 함수 작성이 가능합니다.

    • skip 함수

      1
      2
      3
      4
      5
      var showSkip = function(start){
      return db.info.find().skip(start)
      }

      showSkip(3)

Comment and share

Multi-Thread Programming

Process and Thread

  • Process: OS로부터 메모리를 할당받아 실행중인 프로그램
  • Thread: 프로세스 동작의 최소 단위로, 하나의 프로세스는 여러 스레드로 이루어질 수 있다.

멀티스레드 프로그래밍의 장단점

  • 장점
    • 여러 동작을 병렬적으로 처리하여 CPU의 사용률 향상
    • 시간이 걸리는 동작을 분리하여 프로그램의 응답성 향상
  • 단점
    • Context Switching 오버헤드 발생
    • 스레드 제어의 어려움

스레드 구현

  • 스레드 생성 방법

    1. 익명함수

      1
      2
      3
      4
      5
      Thread threadOne = new Thread(new Runnable() {
      public void run() {
      System.out.println("Hello Thread!");
      }
      });
    2. 람다식

      1
      2
      3
      Thread threadTwo = new Thread(() -> {
      System.out.println("Hello Again, Thread!");
      });
    3. Thread Class 상속

      1
      2
      3
      4
      5
      6
      class MyThread extends Thread {
      public void run() {
      System.out.println("Hello Again Again, Thread!");
      }
      }
      Thread threadThree = new MyThread();
  • 스레드 실행

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    Thread threadOne = new Thread(() -> {
    for (int i = 0; i < 10; i++) {
    System.out.print("1");
    }
    });

    Thread threadTwo = new Thread(() -> {
    for (int i = 0; i < 10; i++) {
    System.out.print("2");
    }
    });

    threadOne.start();
    threadTwo.start();
    System.out.println("Done!");

    Thread 객체는 일회성이기 때문에 여러 번 start()메소드를 호출 할 수 없다


스레드의 상태 및 제어

  • 스레드의 상태

    • getState() 메소드로 스레드의 상태를 확인할 수 있다.

      열거형 상수 설명
      NEW start() 메소드가 아직 호출되지 않음
      RUNNABLE JVM에 의해 실행 가능한 상태
      BLOCKED 객체가 블락된 상태
      WAITING sleep(), wait(), join() 등에 의해 무한히 대기 중인 상태
      TIMED_WAITING sleep(), wait(), join() 등에 의해 정해진 시간 동안 대기 중인 상태
      TERMINATE run() 메소드가 종료된 상태
  • 스레드의 우선순위 제어

    1
    2
    3
    public final static int MIN_PRIORITY = 1;
    public final static int NORM_PRIORITY = 5;
    public final static int MAX_PRIORITY = 10;
    메소드 설명
    void setPriority(int newPriority) 새로운 우선순위로 설정한다.
    int getPriority() 우선순위를 반환한다.
  • sleep()을 이용한 제어

    1
    2
    Thread.sleep(1000); // ms
    Thread.sleep(100, 200); // ms + ns
  • join()을 이용한 스레드 조인

    • 스레드 동작을 동기화하기 위해 사용

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      Thread t1 = new Thread(() -> System.out.println("A"));
      Thread t2 = new Thread(() -> System.out.println("B"));

      t1.start(); // t1 thread start

      t1.join(); // t1 thread 종료시 까지 다른 thread 대기

      t2.start(); // t2 thread start

      t2.join(100); // 100ms 기다린 후에도 t2가 종료되지 않으면 다른 쓰레드 시작

      System.out.println("C");
  • interrupt()를 이용한 대기 중지

    • 기존 동작을 방해하고 반응을 강제하는 메소드
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      Thread tSleep = new Thread(() -> {
      try {
      Thread.sleep(1000);
      } catch (InterruptedException e) {
      System.out.println("Interrupted");
      }
      });

      tSleep.start();

      try {
      Thread.sleep(500);
      } catch (InterruptedException e) {
      e.printStackTrace();
      }

      tSleep.interrupt();
  • yield()를 이용한 상태 제어

    • sleep()과 달리 곧바로 RUNNABLE 상태로 변경
    • 다른 쓰레드에게 양보하고 바로 실행 대기
    • 테스트용으로 쓰임 -> 쓰레드의 동작이 명확하지 않음(바로 양보하지 않는다)
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      new Thread(() -> {
      for (int i = 0; i < 20; i++) {
      if (i % 2 == 0) {
      System.out.print("1");
      } else {
      Thread.yield();
      }
      }
      }).start();

      new Thread(() -> {
      for (int i = 0; i < 20; i++) {
      if (i % 2 == 0) {
      System.out.print("2");
      } else {
      Thread.yield();
      }
      }
      }).start();
  • 스레드의 종료

    • run() 메소드의 종료
    • stop() 메소드 호출 (deprecated)

데몬 스레드

  • 정의 : 다른 스레드가 종료될 경우 함께 종료되는 보조 스레드

  • 활용법

    • 보통 대기하며 동작하는 무한 루프로 구현
    • 일정 시간 마다 동작
    • interrupt에 의해서 동작
  • setDaemon() 메소드로 데몬 스레드로 설정

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    class DaemonThread extends Thread {
    public DaemonThread() {
    this.setDaemon(true);
    }

    @Override
    public void run() {
    while (true) {
    try {
    Thread.sleep(1000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    System.out.println("Daemon Thread Run");
    }
    }
    }

데이터 공유와 동기화

  • 스레드간 데이터 공유 시 신뢰성에 문제가 발생할 수 있음

    결과는 1000000이 나오지 않는다 -> count값이 동기화되지 않았기 때문

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    class Counter {
    int count = 0;
    }
    public class Main {
    public static void main(String args[]){
    Counter counter = new Counter();

    for (int i = 0; i < 1000; i++) {
    new Thread(() -> {
    for (int j = 0; j < 1000; j++) {
    counter.count = counter.count + 1;
    }
    }).start();
    }

    try {
    Thread.sleep(1000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }

    System.out.println(counter.count);
    }
    }
  • synchronized 키워드 사용

    1
    2
    3
    synchronized void method() {
    // 공유 데이터 사용
    }
    1
    2
    3
    4
    5
    void method() {
    synchronized(sharedObj) {
    // 공유 데이터 사용
    }
    }
    • Example

      • this 객체의 Intrinsic Lock을 이용한 구현

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        class Counter {
        private int count = 0;
        public int increaseCount() {
        synchronized (this) {
        return ++count; // 읽고, 수정하고, 쓰는 작업
        }
        }

        public int getCount() {
        return count;
        }
        }
      • 메소드에 synchronized 키워드 사용

        • synchronized 키워드가 사용된 메소드를 호출하기 위해서는 해당 객체를 소유해야만 호출이 가능. 소유하지 못하면 Blocking
          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          class Counter {
          private int count = 0;
          public synchronized int increaseCount() {
          return ++count; // 읽고, 수정하고, 쓰는 작업
          }

          public int getCount() {
          return count;
          }
          }
  • wait(), notify(), notifyAll()

    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
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    class WorkObject {
    public synchronized void methodA() {
    System.out.println("ThreadA의 methodA() 작업 실행");
    notify(); // 일시정지 상태에 있는 ThreadB를 실행 대기상태로 만듬
    try {
    wait(); // ThreadA를 일시 정지 상태로 만듬
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }

    public synchronized void methodB() {
    System.out.println("ThreadB의 methodB() 작업 실행");
    notify(); // 일시정지 상태에 있는 ThreadA를 실행 대기상태로 만듬
    try {
    wait(); // ThreadB를 일시 정지 상태로 만듬
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }
    }


    class ThreadA extends Thread {
    private WorkObject workObject;

    ThreadA(WorkObject workObject) {
    this.workObject = workObject;
    }

    public void run() {
    for(int i=0; i<10; i++) {
    workObject.methodA(); // 공유객체의 methodA를 반복적으로 호출
    }
    }
    }

    class ThreadB extends Thread{
    private WorkObject workObject;

    ThreadB(WorkObject workObject) {
    this.workObject = workObject;
    }

    public void run() {
    for(int i=0; i<10; i++) {
    workObject.methodB(); // 공유객체의 methodA를 반복적으로 호출
    }
    }
    }

    class Main {
    public static void main(String[] args) {
    WorkObject sharedObject = new WorkObject();

    ThreadA threadA = new ThreadA(sharedObject);
    ThreadB threadB = new ThreadB(sharedObject);

    threadA.start();
    threadB.start();
    }
    }

세마포어

  • 사전적 의미 : 횟대(깃발)

  • n개의 깃발을 놓고, 여러 스레드가 경쟁하도록 하는 sync 기법

  • n = 1이면, BinarySemaphore라고 하며, Lock과 유사하게 동작

  • 메소드

    • release(int permits) : permits만큼의 자원 개수 반환
    • acquire(int permits) : permits만큼의 자원 사용 (Blocking O)
    • tryAcquire(long timeout, TimeUnit unit) : unit단위의 timeout이후 자원을 얻지 못하면 false, 얻으면 true (Blocking X)
    • acquireUninterruptibly() : 자원을 얻지못해도 interrupt 발생 X
  • Example

    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
    public class Main {
    public static void main(String[] args) {
    Semaphore sem = new Semaphore(1);

    sem.release(10);
    sem.tryAcquire();
    System.out.println(sem.availablePermits());

    try { // Blocking으로 동작
    sem.acquire(12);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }

    sem.acquireUninterruptibly(); // interrupt에 반응하지 않음
    try {
    System.out.println(sem.tryAcquire(100, TimeUnit.MILLISECONDS)); // Blocking 하지 않고, 실패하면 false
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    sem.release();

    System.out.println(sem.availablePermits());
    }
    }
  • Dining Philosopher (식사하는 철학자)

    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
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    class Philosopher extends Thread {
    private final int id;
    private final Fork left;
    private final Fork right;

    public Philosopher(int id, Fork left, Fork right) {
    this.id = id;
    this.left = left;
    this.right = right;
    }

    @Override
    public void run() {
    while (true) {
    try {
    left.acquire();
    System.out.println(id + ": left taken");
    } catch (InterruptedException e) {
    e.printStackTrace();
    }

    try {
    if(!right.tryAcquire(1000, TimeUnit.MILLISECONDS)){
    left.release();
    Thread.yield();
    continue;
    }
    System.out.println(id + ": right taken");
    } catch (InterruptedException e) {
    e.printStackTrace();
    }

    try {
    Thread.sleep(2000);
    System.out.println(id + "is eating");
    } catch (InterruptedException e) {
    e.printStackTrace();
    }

    left.release();
    right.release();
    Thread.yield();
    }
    }
    }

    class Fork extends Semaphore {

    public Fork() {
    super(1);
    }
    }
    public class Main {
    public static void main(String[] args) {
    Philosopher[] phils = new Philosopher[5];
    Fork[] forks = new Fork[5];

    for (int i = 0; i < 5; i++) {
    forks[i] = new Fork();
    }

    for (int i = 0; i < 5 - 1; i++) {
    phils[i] = new Philosopher(i, forks[i], forks[(i+1) % 5]);
    }

    phils[4] = new Philosopher(4, forks[0], forks[4]);
    for (int i = 0; i < 5; i++){
    phils[i].start();
    }
    }
    }

JCF와 Thread

  • Vector VS List

    • List
      • 메소드들이 Synchronized 되지 않음
      • 속도는 빠르다.
    • Vector
      • 메소드들이 Synchronized 되어 있음
      • 속도는 느리다.
  • List를 Synchronized 되게 하는 방법

    • Collections의 synchronizedList() 사용
      1
      2
      List<Integer> list1 = new ArrayList<>();
      List<Integer> list2 = Collections.synchronizedList(list1);

      Thread Pool

  • Thread Pool이란?

    • 미리 생성해 둔 Thread의 집합을 스레드 풀이라고 한다.
    • 미리 Thread를 생성해 두고, 작업만 Thread에 할당하여 동작
    • 사용 이유
      • Thread를 직접 만들어 사용할 경우, Multi-Thread 작업을 계속 할 때, Thread 생성/삭제 오버해드가 크다.
      • 배치작업 (모아두고 한 번에 처리하는 작업)에 유용하여 많이 사용된다.
  • Thread Pool 생성

    • Single Thread Pool

      1
      ExecutorService pool = Executors.newSingleThreadExecutor();
      • Thread가 1개인 ThreadPool 생성(SingleThread)
      • 실패 시, 새로운 Thread를 생성하지 않음
    • Cached Thread Pool

      1
      ExecutorService pool = Executors.newCachedThreadPool();
      • 초기 Thread 0개
      • 코어 Thread 0개 (일하지 않아도 종료시키지 않는 Thread)
      • 요청 작업보다 Thead가 부족하면 새 스레드 생성
      • 60초동안 일하지 않는 Thread 제거
    • Fixed Thread Pool

      1
      ExecutorService pool = Executors.newFixedThreadPool(int nThreads);
      • 최대 Thread nThreads개
      • 코어 Thread nThreads개
      • 작업하지 않는 Thread도 제거하지 않고 동작
    • Scheduler Thread Pool

      1
      ScheduledExecutorService pool = Executors.newScheduledThreadPool(int corePoolSize);
      • 지정된 delay후에 실행하도록함(주기적으로 실행하는 명령을 예약)
  • 작업 생성과 처리 요청

    • 작업 생성

      • Runnable 구현 클래스

        1
        2
        3
        4
        5
        6
        Runnable task = new Runnable(){
        @Override
        public void run(){
        // 작업 내용
        }
        }
      • Callable 구현 클래스

        1
        2
        3
        4
        5
        6
        7
        Callable<T> task = new Callable<T>(){
        @Override
        public T call() throws Exception{
        // 작업 내용
        return T;
        }

        Runnable run()은 Return 값이 없고, Callable call()은 Return 값이 있음

    • 처리 요청

      • 매소드

        리턴 타입 메소드 설명
        void execute(Runnable command) Runnable을 작업 큐에 저장, 작업 처리 결과를 받지 못함
        Future<?> submit(Runnable task) Runnable 작업 큐에 저장, 리턴된 Future를 통해 작업 처리 결과를 얻을 수 있음
        Future submit(Runnable task, V result) Runnable 작업 큐에 저장, 리턴된 Future를 통해 작업 처리 결과를 얻을 수 있음
        Future submit(Callable task) Callable 작업 큐에 저장, 리턴된 Future를 통해 작업 처리 결과를 얻을 수 있음
        • execute()

          • 작업 처리 결과를 반환하지 않는다.

          • 작업 처리 도중 예외가 발생하면 스레드가 종료되고 해당 스레드는 스레드 풀에서 제거된다.

          • 다른 작업을 처리하기 위해 새로운 스레드를 생성한다.

        • submit()

          • 작업 처리 결과를 반환한다.

          • 작업 처리 도중 예외가 발생하더라도 스레드는 종료되지 않고 다음 작업을 위해 재사용

          • 스레드의 생성 오버헤드를 방지하기 위해서라도 submit() 을 가급적 사용한다.

  • Thread Pool 종료

    Thread Pool에 속한 Thread는 데몬 스레드가 아니다

    따라서 주 스레드 종료시 강제종료 되지 않기 때문에 main 스레드가 종료되어도 실행상태가 유지된다.

    어플리케이션을 종료하기 위해서는 스레드 풀을 강제종료시켜야 한다.

    • excutorService.shutdown()

      작업큐에 남아있는 작업까지 모두 마무리 후 종료 (오버헤드를 줄이기 위해 일반적으로 많이 사용.)

    • excutorService.shoutdownNow()

      작업큐 작업 잔량 상관없이 강제 종료

    • excutorService.awaitTermination(long timeout, TimeUnit unit)

      모든 작업 처리를 timeout 시간안에 처리하면 true 리턴 ,처리하지 못하면 작업스레드들을 interrupt()시키고 false리턴

Comment and share

백준 1766 : 문제링크

  • 문제유형

    • 탐색
    • 위상정렬
  • 설명

    • 위상정렬
      1. 진입 차수가 0인 정점을 큐에 삽입
      2. 큐에서 원소를 꺼내 해당 원소와 간선을 제거
      3. 제거 이후 진입 차수가 0이 된 정점을 큐에 삽입
      4. 큐가 빌 때까지 2 ~ 3을 반복
    • 위상정렬 사용이유 : 2번 조건 - 먼저 푸는 것이 좋은 문제가 있는 문제는, 먼저 푸는 것이 좋은 문제를 반드시 먼저 풀어야 한다.)
    • 힙 사용이유 : 3번 조건 - 가능하면 쉬운 문제부터 풀어야 한다
  • 풀이

    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
    29
    30
    import heapq

    n, m = map(int, input().split())
    array = [[] for i in range(n + 1)]
    indegree = [0] * (n + 1)

    heap = []
    result = []

    for _ in range(m):
    x, y = map(int, input().split())
    array[x].append(y)
    indegree[y] += 1

    for i in range(n+1):
    if indegree[i] == 0:
    heapq.heappush(heap, i)

    result = []

    while heap:
    data = heapq.heappop(heap)
    result.append(data)
    for y in array[data]:
    indegree[y] -= 1
    if indegree[y] == 0:
    heapq.heappuh(heap, y)

    for i in result:
    print(i, end = ' ')

Comment and share

백준 1715 : 문제링크

  • 문제유형 :

    • 탐색
    • 그리디
  • 설명

    • 가장 작은 숫자의 카드 묶음을 먼저 합쳤을 때 최소값
    • heap을 사용해서 작은 값 두개를 pop한다
    • 추출한 두 개의 값을 합해서 결과에 더한다
    • 합한 값을 다시 heap에 push한다
    • heap에 값이 한 개 남았을 때 종료한다
  • 풀이

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    import heapq

    n = int(input())
    heap = []

    for i in range(n):
    data = int(input())
    heaq.heappush(heapq, data)

    result = 0

    while len(heap) != 1:
    one = heapq.heappop(heap)
    two = heapq.heappop(heap)
    sum_value = one + two
    result += sum_value
    heapq.heappush(heap, sum_value)

    print(result)

Comment and share

VIEW

Explain

  • 가상 테이블로 일부분만 데이터로 보고자 할때 사용합니다.

  • 실제 데이터를 저장하고 있지는 않습니다.

  • 한마디로 특정 컬럼의 데이터를 보여주는 역할만 합니다.

  • 뷰를 사용함으로 쿼리를 더 단순하게 만들수 있습니다.

  • 한번 생성된 뷰는 수정이 불가능 하며 인덱스설정이 불가능 합니다.

Syntax

1
CREATE VIEW <뷰이름> AS (QUERY)

Example

  • 국가코드와 국가이름이 있는 뷰

    1
    2
    3
    CREATE VIEW code_name AS
    SELECT code, name
    FROM country
  • city 테이블에 국가 이름 추가

    1
    2
    3
    4
    SELECT *
    FROM city
    JOIN code_name
    ON city.countrycode = code_name.code

INDEX

Explain

  • 정의 : 테이블에서 데이터를 검색할때 빠르게 찾을수 있도록 해주는 기능입니다.

  • 장점 : 검색속도가 빨라짐

  • 단점 : 저장공간을 10% 정도 더 많이 차지 INSERT, DELETE, UPDATE 할때 속도가 느려짐

  • 사용법 : SELECT시 WHERE 절에 들어가는 컬럼을 Index로 설정하면 좋다.

  • 내부 작동 원리 (B-Tree)

    • 루트노드와 리프노드의 계층적 구조로 루트노드를 이용하여 리프노드에서의 데이터를 빠르게 찾을수 있는 자료구조 알고리즘.

Syntax

1
CREATE INDEX <인덱스 이름> AS <테이블 이름(필드 이름)>

Example

  • employees 데이터 베이스에서 실행

  • 실행계획을 확인하여 인덱스를 사용하는지 확인

    1
    2
    3
    4
    5
    6
    7
    8
    9
    EXPLAIN
    SELECT *
    FROM salaries
    WHERE from_date < "1986-01-01"

    EXPLAIN
    SELECT *
    FROM salaries
    WHERE to_date < "1986-01-01"
  • 인덱스 확인

    1
    SHOW INDEX FROM salaries;
  • 인덱스 생성

    1
    2
    3
    4
    5
    CREATE INDEX fdate
    ON salaries (from_date)

    CREATE INDEX tdate
    ON salaries (to_date)
  • 여러개의 컬럼을 가지는 인덱스 생성도 가능

    1
    2
    CREATE INDEX ftdate
    ON salaries (from_date, to_date)
  • 인덱스 삭제

    1
    2
    3
    4
    5
    6
    7
    8
    DROP INDEX fdate
    ON salaries

    DROP INDEX tdate
    ON salaries

    DROP INDEX ftdate
    ON salaries
  • 여러개의 컬럼을 조건으로 WHERE절에 사용하는 경우 인덱스 확인

  • 인덱스가 하나의 컬럼에 있을때 보다 둘다 있을때가 더 빠름

    1
    2
    3
    4
    EXPLAIN
    SELECT *
    FROM salaries
    WHERE from_date < "1986-01-01" AND to_date < "1986-01-01"

TRIGGER

정의 : 특정 테이블을 감시하고 있다가 설정된 조건의 쿼리가 실행되면 미리 지정한 쿼리가 자동으로 실행되도록하는 방법

Syntax

1
2
3
4
5
6
create trigger {trigger name}
{before | after} {insert | update |delete}
on <table name> for each row
begin
<excute query>
end

Example

  • database 생성

    1
    2
    3
    4
    5
    6
    7
    8
    9
    create table data1 (
    id varchar(20),
    msg varchar(50) not null
    );

    create table data_backup (
    id varchar(20),
    msg varchar(50) not null
    );
  • Trigger 생성

    1
    2
    3
    4
    5
    6
    7
    create trigger backup
    before delete on data1
    for each row
    begin
    insert into data_backup(id, msg)
    values(old.id, old.msg);
    end

Comment and share

Sub Query

sub query는 query 문 안에 있는 query를 의미합니다.

SELECT절, FROM절, WHERE 등에 사용이 가능합니다.

Example

  • 전체 나라수, 전체 도시수, 전체 언어수를 출력 ( SELECT 절에 사용 )

    SUB QUERY 사용시 JOIN TABLE 크기를 줄일 수 있다

    1
    2
    3
    4
    5
    SELECT
    (SELECT count(name) FROM city) AS total_city,
    (SELECT count(name) FROM country) AS total_country,
    (SELECT count(DISTINCT(Language)) FROM countrylanguage) AS total_language
    FROM DUAL
  • 800만 이상되는 도시의 국가코드, 이름, 도시인구수를 출력 ( FROM 절에 사용 )

    • SUB QUERY를 안 쓸때

      • city table row : 4079
      • coutnry table row : 239
      • JOIN TABLE : 4079 * 239
        1
        2
        3
        4
        5
        6
        7
        8
        SELECT *
        FROM
        city
        JOIN
        (SELECT code, name
        FROM country) AS country
        ON city.countrycode = country.code
        HAVING city.population > 8000000;
    • SUB QUERY를 쓸 때

      • city table row : 10
      • coutnry table row : 239
      • JOIN TABLE : 10 * 239
        1
        2
        3
        4
        5
        6
        7
        8
        9
        SELECT *
        FROM
        (SELECT countrycode, name, population
        FROM city
        WHERE population > 8000000) AS city
        JOIN
        (SELECT code, name
        FROM country) AS country
        ON city.countrycode = country.code;

  • 800만 이상 도시의 국가코드, 국가이름, 대통령이름을 출력( WHERE 절에 사용 )

    1
    2
    3
    4
    5
    SELECT code, name, HeadOfState
    FROM country
    WHERE code IN (
    SELECT DISTINCT(countrycode) FROM city WHERE population > 8000000
    )

Comment and share

백준 1927 : 문제링크

  • 문제유형 :

    • 탐색

  • 설명

    • 파이썬에서 heapq 라이브러리를 이용하면 힙 구현 가능하다.
  • 풀이

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    import heapq

    n = int(input())
    heap = []
    result = []

    for _ in range(n):
    data = int(input())
    if data = 0:
    if heap:
    result.append(heapq.heappop(heap))
    else:
    result.append(0)
    else:
    heapq.heappush(heap, data)

    for data in result:
    print(data)

Comment and share

Yechan Kim

author.bio


author.job