java 8 정리8

Java 정리 2021. 6. 2. 20:40

인프런 강의 10일차. (9일차에 이어서 같은 Callable 강의)

 - 더 자바, Java 8 (백기선 강사님)

 

1. Date/Time 소개

 - 자바 8에 새로운 날짜와 시간 API가 생긴 이유

 - 그전까지 사용하던 java.util.Date 클래스는 mutable(상태를 바꿀 수 있다)하기 때문에 thread safe하지 않다.

 - 클래스 이름이 명확하지 않다. (Date인데 시간까지 다룬다)

 - 버그 발생할 여지가 많다. (타입 안정성이 없고, 월이 0부터 시작한다거나.. 등등)

 - 날짜 시간 처리가 복잡한 애플리케이션에서는 보통 Joda Time을 쓰곤했다.

 - setTime으로 시간 변경이 가능하기 때문에 mutable하다

 

2. 자바 8에서 제공하는 Date-Time API

 - JSR-310 스팩의 구현체를 제공한다.

 - 디자인 철학

   > Clear

   > Fluent

   > Immutable

   > Extensible

 

3. 주요 API
 - 기계용 시간(machine time)과 인류용 시간(human time)으로 나눌 수 있다.

 - 기계용 시간은 EPOCK (1970년 1월 1일 0시 0분 0초)부터 현재까지의 타임스탬프를 표현한다.

 - 인류용 시간은 우리가 흔히 사용하는 연, 월, 일, 시, 분, 초 등을 표현한다.

 - 타임스탬프는 Instant를 사용한다.

 - 특정 날짜(LocalDate), 시간(LocalTime), 일시(LocalDateTime)을 사용할 수 있다.

 - 기간을 표현할 때는 Duration(시간 기반)과 Period(날짜 기반)을 사용할 수 있다.

 - DateTimeFormatter를 사용해서 일시를 특정한 문자열로 포매팅할 수 있다.

 

4. 현재 시간을 기계 시간으로 표현하는 방법

 - instant.now() : 현재 UTC (GMT)를 리턴한다.

 - Universal Time Coordinated == Greenwich Mean Time

Instant now = Instant.now();
System.out.println(now);
System.out.println(now.atZone(ZoneId.of("UTC")));

ZonedDateTime zonedDateTime = now.atZone(ZoneId.systemDefault());
System.out.println(zonedDateTime);

 

5. 인류용 일시를 표현하는 방법

 - LocalDateTime.now() : 현재 시스템 Zone에 해당하는 로컬 일시를 리턴한다.

 - LocalDateTime.of(int, Month, int, int, int, int) : 로컬의 특정 일시를 리턴한다.

 - ZonedDateTime.of(int, Month, int, int, int, int, ZonedId) : 특정 Zone의 특정 일시를 리턴.

 

6. 기간을 표현하는 방법

 - Period / Duratio . betwwen()

Period between = Period.between(today, birthDay);	//Period : 휴먼시간을 비교
System.out.println(between.get(ChronoUnit.MONTHS));	//Duration : 기계시간을 비교

 

7. 파싱 또는 포맷팅

 - 미리 정의해준 포맷 참고 : docs.oracle.com

 - LocalDateTime.parse(String, DateTimeFormatter);

DateTimeFOrmatter fomatter = DateTimeFormatter.ofPattern("MM/d/yyyy");
LocalDate date = LocalDate.parse("07/15/1982", formatter);
System.out.println(date);
System.out.println(today.format(fomatter));

 

8. 레거시 API 지원

 - GregorianCalendar와 Date 타입의 인스턴스를 Instant나 ZonedDateTime으로 변환 가능

 - java.util.TimeZone에서 java.time.ZoneId로 상호 변환 가능

ZoneId newZoneAPI = TimeZone.getTimeZone("PST").toZoneId();
TimeZone legacyZoneAPI = Time.Zone.getTimeZone(newZoneAPI);
Instant newInstant = new Date().toInstant();
Date legacyInstant = Date.from(newInstant);

 

9. Date 연산

LocalDateTime now = LocalDateTime.now();
now.plus(10, ChronoUnit.DAYS);	//날짜는 immutable 해야하기 때문에 return 받는 변수가 없으면 아무 일도 일어나지 않는다.
LocalDateTime plus10now = now.plus(10, ChronoUnit.DAYS);	//오늘 + 10일을 한 날짜는 새로 변수에 할당

 

'Java 정리' 카테고리의 다른 글

java 8 정리10  (0) 2021.06.30
java 8 정리9  (0) 2021.06.17
java 8 정리7  (0) 2021.05.26
java 8 정리6  (0) 2021.05.21
java 8 정리5  (0) 2021.05.20

java 8 정리7

Java 정리 2021. 5. 26. 12:03

인프런 강의 9일차.

 - 더 자바, Java 8 (백기선 강사님)

 

1. Callable

 - Runnable과 유사하지만 작업의 결과를 받을 수 있다.

 

2. Future

 - 비동기적인 작업의 현재 상태를 조회하거나 결과를 가져올 수 있다.

 - 결과를 가져오기 get()

ExecutorService executorService = Executors.newSingleThreadExecutor();
Future<String> helloFuture = executorService.submit(() -> {
	Thread.sleep(1000);
   	return "Callable";
});
System.out.println("Hello");
String result = helloFuture.get();
System.out.println(result);
executorService.shutdown();

 - 블록킹 콜이다.

 - 타임아웃(최대한 기다릴 시간)을 정할 수 있다.

 

3. 작업 상태 확인하기 isDone()

 - 완료 했으면 true, 아니면 false를 리턴

 

4. 작업 취소하기 cancel()

 - 취소 했으면 true, 못했으면 false를 리턴

 - parameter로 true를 전달하면 현재 진행중인 쓰레드를 interrupt하고 그러지 않으면 현재 진행중인 작업이 끝날 때 까지 기다린다.

 

5. 여러 작업 동시에 실행하기 invokeAll()

 - 동시에 실행한 작업 중에 제일 오래 걸리는 작업 만큼 시간이 걸린다.

 

6. 여러 작업 중에 하나라도 먼저 응답이 오면 끝내기 invokeAny()

 - 동시에 실행한 작업 중에 제일 짧게 걸리는 작업 만큼 시간이 걸린다.

 - 블록킹 콜이다.

 

package me.whiteship.java8to11;

import java.sql.SQLOutput;
import java.util.Arrays;
import java.util.concurrent.*;

public class App {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executorService = Executors.newSingleThreadExecutor();

        Callable<String> hello = () -> {
            Thread.sleep(2000L);
            return "Hello";
        };

        Callable<String> java = () -> {
            Thread.sleep(3000L);
            return "Java";
        };

        Callable<String> dhpark = () -> {
            Thread.sleep(1000L);
            return "dhpark";
        };

        //3개의 Callable을 하나의 Collection으로 넘겨서 주면 Future의 List가 나오고, 그에 대해 3개의 Callable을 한번에 수행한다.
        executorService.invokeAll(Arrays.asList(hello, java, dhpark));

        Future<String> helloFuture = executorService.submit(hello);
        System.out.println("Started!!!");       //get을 수행하기 전 까지는 코드가 쭉 실행이 된다,

        helloFuture.cancel(false);  //cancel을 하게 되면 isDone은 무조건 true가 된다!

        //get을 만나는 순간 결과값을 가져올 때 까지 기다린다(=블록킹 콜)
        //만약 cancel이 된 Future를 get하게 된다면 익셉션이 발생한다.
        helloFuture.get();

        String s = executorService.invokeAny(Arrays.asList(hello, java, dhpark));//any이므로 하나가 끝나면 바로 결과가 나온다
        //가장 짧은 timeout인 dhpark이 호출된다.
        //단 이 때 쓰레드의 타입 및 개수에 따라 다음과 같은 아웃풋이 나온다.
        //SingleThread로 선언된 경우 첫 Callable이 끝날 때 가지 다음 Callable을 호출하지 못 하므로 첫번째 Callable인 Hello 호출
        //fixedThread(2)로 선언 된 경우 dhpark은 들어갈 자리가 없으므로 앞의 2개의 Callable 중 먼저 끝나는 Hello가 출력
        //fixedThread(4)로 선언 된 경우 가장 짧은 Callable인 dhpark이 출력
        System.out.println(s);

        System.out.println(helloFuture.isDone());
        System.out.println("End!!!!");
        executorService.shutdown();
    }
}

'Java 정리' 카테고리의 다른 글

java 8 정리9  (0) 2021.06.17
java 8 정리8  (0) 2021.06.02
java 8 정리6  (0) 2021.05.21
java 8 정리5  (0) 2021.05.20
java 8 정리4  (0) 2021.05.19

java 8 정리6

Java 정리 2021. 5. 21. 14:34

인프런 강의 8일차.

 - 더 자바, Java 8 (백기선 강사님)

 

1. 자바에서 지원하는 Concurrent 프로그래밍

 - 멀티프로세싱 (ProcessBuilder)

 - 멀티쓰레드

 

2. 자바 멀티쓰레드 프로그래밍

 - Thread / Runnable

 - Thread 상속

public static void main(String[] args){
  HelloThread helloThread = new HelloThread();
  helloThraed.start();
  System.out.println("hello = "+ Thread.currentThread().getName());
}

static class HelloThread extends Thread {
  @Override
  public void run() {
  System.out.println("World = "+ THread.currentThread().getName());
}

 - Runnable 구현 또는 람다

Thread thread = new Thread(() -> System.out.println("World = "+Thread.currentThread().getName()));
thread.start();
System.out.println("Hello = "+ Thread.currentThread().getName());

 - 쓰레드 주요 기능

   > 현재 쓰레드 멈춰두기(sleep) : 다른 쓰레드가 처리할 수 있도록 기회를 주지만, 그렇다고 락을 놔주진 않는다. (잘못하면 데드락이 걸릴 수 있다)

   > 다른 쓰레드 깨우기(interupt) : 다른 쓰레드를 깨워서 interruptedException을 발생 시킨다. 그 에러가 발생했을 때 할 일은 코딩하기 나름. 종료시킬 수도 있고, 계속 하던 일 할 수도 있고, 사용자 구현 가능

   > 다른 쓰레드 기다리기(join) : 다른 쓰레드가 끝날 때 까지 기다린다.

 

package me.whiteship.java8to11;

import ch.qos.logback.core.util.ExecutorServiceUtil;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class App {

    public static void main(String[] args) throws InterruptedException {
        MyThread myThread = new MyThread();
        myThread.start();
        System.out.println("Hello");

        Thread thread = new Thread(() -> {
            while(true) {
                try {
                    Thread.sleep(3000L);
                } catch (InterruptedException e) {
                    //InterruptedException은 누군가 이 쓰레드를 깨울 때 동작한다.
                    System.out.println("Interrupted!!");
                    return;
                }
            }
        });
        thread.start();

        System.out.println("Thread : " + Thread.currentThread().getName());
        //Thread.sleep(3000L);
        //thread.interrupt(); 쓰레드 인터럽트 발생
        thread.join();  //위 쓰레드가 끝날 때 까지 기다린다.
        System.out.println(thread + " is finished");    //join()으로 인해 위 쓰레드 종료될 때 가지 기다린 후 출력됨

        //join으로 다른 쓰레드 기다리는 와중에 또 다른 쓰레드에서 인터럽트 발생 시 복잡도가 기하급수적으로 늘어난다
        //여러개의 쓰레드를 코딩으로 관리하는 것은 비효율적 & 어렵기 때문에 executor가 나왔다.
    }

    static class MyThread extends Thread {
        @Override
        public void run() {
            System.out.println("Thread : " + Thread.currentThread().getName());
        }
    }
}

 

3. Executors

 - 고수준(High-Level) Cuncurency 프로그래밍

   > 쓰레드를 만들과 관리하는 작업을 애플리케이션에서 분리

   > 그런 기능을 Executors에게 위임

 

 - Executors가 하는 일

   > 쓰레드 만들기 : 애플리케이션이 사용할 쓰레드 풀을 만들어서 관리한다.

   > 쓰레드 관리 : 쓰레드 생명 주기를 관리한다

   > 작업 처리 및 실행 : 쓰레드로 실행할 작업을 제공할 수 있는 API를 제공한다.

 

 - 주요 인터페이스

   > Executor: execute(Runnable)

   > ExecutorService : Executor 상속 받은 인터페이스로, Callable도 실행할 수 있으며, Executor를 종료시키거나, 여러 Callable을 동시에 실행하는 등의 기능을 제공한다.

   > ScheduledExecutorService : ExecutorService를 상속 받은 인터페이스로 특정 시간 이후에 또는 주기적으로 작업을 실행할 수 있다.

 

 - ExecutorService로 작업 실행하기

ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.submit(() -> {
	System.out.println("Hello = " + Thread.currentThread().getName());
}

 

 - ExecutorService로 멈추기

executorService.shutdown();		//처리중인 작업 기다렸다가 종료
executorService.shutdownNow();	//당장 종료

 

 - Fork/Join 프레임워크

   > ExecutorService의 구현체로 손쉽게 멀티 프로세서를 활용할 수 있게끔 도와준다.

 

package me.whiteship.java8to11;

import java.sql.SQLOutput;
import java.util.concurrent.*;

public class App {

    public static void main(String[] args) throws InterruptedException {
        /*ExecutorService executorService = Executors.newSingleThreadExecutor();
        executorService.submit(() -> {  //executorService는 만들어서 실행하게 되면 다음 작업이 들어올 때 까지 계속 대기하므로 명시적으로 shutdown을 해주어야 한다.
            System.out.println("Thread : "+Thread.currentThread().getName());
        });*/

        //쓰레드는 2개지만 5개의 작업 실행
        ExecutorService executorService = Executors.newFixedThreadPool(2);

        //2개의 쓰레드가 나눠서 5개의 작업을 수행한다.
        executorService.submit(getRunnable("Hello"));
        executorService.submit(getRunnable("World"));
        executorService.submit(getRunnable("dhpark"));
        executorService.submit(getRunnable("Java"));
        executorService.submit(getRunnable("Thread"));

        executorService.shutdown();     //graceful shutdown이라고 한다. (현재 진행중인 작업을 전부 마치고 종료)
        //executorService.shutdownNow();  //현재 돌고 있는 쓰레드 종료여부와 상관없이 바로 종료*/

        ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
        scheduledExecutorService.schedule(getRunnable("Hello"), 3, TimeUnit.SECONDS);   //3초 정도 딜레이 후 getRunnable 실행
        scheduledExecutorService.scheduleAtFixedRate(getRunnable("fixedHello"), 1, 2. TimeUnit.SECONDS);    //1초만 기다렸다가 2초에 한번씩 출력

    }

    private static Runnable getRunnable(String message){
        return () -> System.out.println(message + Thread.currentThread().getName());
    }
}

 

 

'Java 정리' 카테고리의 다른 글

java 8 정리8  (0) 2021.06.02
java 8 정리7  (0) 2021.05.26
java 8 정리5  (0) 2021.05.20
java 8 정리4  (0) 2021.05.19
java 8 정리3  (0) 2021.05.17