슈퍼코딩/주특기(JAVA)

2024.05.16(목) 슈퍼코딩 신입연수원 7주차 Day 4 후기 - 신입 개발자 역량, 메소드 레퍼런스, 멀티 쓰레딩 프로그래밍

곰돌이볼 2024. 5. 16. 08:29

 


신입 개발자에게 원하는 것 


  • 돌아가는 판의 흐름을 읽고 이해하기
  • 돌아가는 판
    • 다양한 자바 프레임워크
    • 다양한 자바 라이브러리
    • 복잡하고 많은 코드
  • 실무를 위해 익혀야 하는 기술과 지식
    • 자바
      • AOP
      • clean code
      • optimizing
      • 디자인 패턴
    • spring
    • lombok
    • jcoco
    • mockito
  • 회사 실무 코드의 흐름을 일기 위해서 → 모든 프레임워크, 라이브버리, 고급 기술을 익힐 필요 X
    • 자주 사용하는 일부분만 알아도 됨

메소드 레퍼런스


  • 자바 함수 가독성 진화
    • 일반 함수 → 람다식 → 메소드 레퍼런스
  • Java 8 이후 지원
  • 메서드를 참조해서 해당 메소드의 동작을 다른 코드엥서 재사용할 수 있는 기능
  • 호출 : Class::MethodName
    Consumer<String> func = text -> System.out.println(text); // 람다식
    Consumer<String> func = System.out::println; // 메소드 레퍼런스
  • 자주 사용되는 함수형 인터페이스
함수형 인터페이스 파라미터 타입 반환 타입 추상 메서드 이름 설명
Supplier 없음 T get T 타입 값 제공
Consumer T void accept T 타입 값 소비
Function<T,R> T R apply T 타입 인자 받음
BiFunction<T,U,R> T,U R apply T와 U타입 인자 받음
Predicate T boolean test Boolean값 반환
@FunctionalInterface
public interface Supplier<T> {

    /**
     * Gets a result.
     *
     * @return a result
     */
    T get();
}

@FunctionalInterface
public interface Consumer<T> {

    /**
     * Performs this operation on the given argument.
     *
     * @param t the input argument
     */
    void accept(T t);
}

 

 

public class MethodReferenceTest1 {
    public static void main(String[] args) {
        // static method
        Consumer<String> ex1 = (str) -> Printer.printSomething(str); // Lambda Expression
        Consumer<String> ex2 = Printer::printSomething; // Method Reference
        ex1.accept("Lamda 식 사용"); // Lamda 식 사용를 출력합니다.
        ex1.accept("메서드 레퍼런스 사용"); // 메서드 레퍼런스 사용를 출력합니다.

        // 생성자 호출
        Supplier<Customer> ex3 = () -> new Customer(); // Lambda Expression
        Supplier<Customer> ex4 = Customer::new; // Method Reference
        System.out.println(ex3.get()); // Customer [name=홍길동]
        System.out.println(ex4.get()); // Customer [name=홍길동]

        Function<String, Customer> ex5 = (name) -> new Customer(name); // Lambda Expression
        Function<String, Customer> ex6 = Customer::new; // Method Reference
        System.out.println(ex5.apply("홍길동")); // Customer [name=홍길동]
        System.out.println(ex6.apply("홍길동")); // Customer [name=홍길동]

        // Instance method 참조
        Customer customer = new Customer("임한별");
        Customer customer1 = new Customer("이지은");

        Supplier<String> ex7 = customer::toString; // Lambda Expression
        Supplier<String> ex8 = customer1::toString; // Method Reference
        System.out.println(ex7.get()); // Customer [name=임한별]
        System.out.println(ex8.get()); // Customer [name=이지은]

        // 임의 인스턴스 method 참조
        List<Customer> customerList = Arrays.asList(
                new Customer("임한별"),
                new Customer("이지은"),
                new Customer("박하나"),
                new Customer("김창조")
        );

        customerList.forEach(Customer::printInfo);
        /*
        Customer [name=임한별]
        Customer [name=이지은]
        Customer [name=박하나]
        Customer [name=김창조]
         */

    }
}

 

  • 사용
    • static method 참조 : stream의 filter, forEach 등
    • 생성자 참조 : stream의  map 등
    • 객체 인스턴스 메소드 참조 : stream의  filter 등
    • 임의 인스턴스 메서드 참조 : stream의  map, forEach 등
  • 사용 이유
    • 가독성 ↑
    • 취향에 따라서 선택 사용 가능

멀티 쓰레딩 프로그래밍


Thread

  • 프로세스 내 동시에 동작하는 작업 단위
  • 사용 이유
    • 병렬 처리
    • 속도 증가
  • java의 Thread
    • main thread에서 시작
    • 작업 순서
      • thread 객체 생성(NEW) → 실행 대기(Runnable) → 실행 → 종료(Terminated)
      • 실행 대기와 실행을 반복함
      • Runnable 함수형 인터페이스를 상속받아서 구현 및 사용
  • 코드 예시
    • 동작 순서는 항상 다를 수 있음
public class Threading {
    public static void main(String[] args) {
        // thread 실행
        Thread thread = new Thread(new MyThread());
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("Thread >> " + Thread.currentThread().getName() + " is running");
            }
        });
        Thread thread2 = new Thread(() -> System.out.println("Thread >> " + Thread.currentThread().getName() + " is running"));

        System.out.println("Thread >> " + Thread.currentThread().getName() + " is running");
        // Thread >> main is running

        // 동작 시작
        thread.start(); // Thread >> Thread-0 is running
        thread1.start(); // Thread >> Thread-1 is running
        thread2.start(); // Thread >> Thread-2 is running

    }

    static class MyThread implements Runnable {
        @Override
        public void run() {
            System.out.println("Thread >> " + Thread.currentThread().getName() + " is running");
        }
    }
}

 

멀티 쓰레딩 프로그래밍(Multi Thread Programming)

public class MultiThreading {
    public static void main(String[] args) {
        // Q) 1 ~ 100 까지 숫자를 출력하는데, Multi Thread를 사용해서 일 분담

        // A) 2명 Thread 사용
        Thread thread1 = new Thread(new PrintNumberRunnable(1, 50));
        Thread thread2 = new Thread(new PrintNumberRunnable(51, 100));

        thread1.start();
        thread2.start();
        // 51 1 52 53 2 54 3 55 4 56 5 57 6 7 8 9 58 59 10 60 61 11 62 12 63 13 64 14 65 15 66 16 67 17 18 19 20 68 69 70 71 72 73 21 22 74 75 23 76 24 25 26 27 28 29 30 31 32 33 77 34 78 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
        // 두 개의 thread가 동시에 진행되서 숫자가 정렬되어 있지 않음
    }
}
  • 주의할 점
    • thread 들의 순서는 보장 X
    • thread 들은 각자의 개별 영역이 있고, 공통 영역인 method area, heap area 존재
  • 문제점
    • thread들이 공통 영역을 동시에 접근하여 수정할 때 일관성 및 충돌 문제 발생
    • 해결방법
      • thread 동작이 끝날 때까지 다른 thread들 동작 X → 동작 완료 후 다른 thread 동작 가능
      • Synchronized(동기화) 키워드 이용
  • Synchronized 코드
public class MultiThreadingIssue {
    public static void main(String[] args) {
        Counter counter = new Counter(); // heap(공통 영역)에 new Counter가 생성되어 있음

        Thread thread1 = new Thread(new IncrementRunnable(counter));
        Thread thread2 = new Thread(new IncrementRunnable(counter));
        Thread thread3 = new Thread(new IncrementRunnable(counter));

        // thread가 동시 진행되면서 thread들이 겹쳐서 3000까지 제대로 출력하지 못함
        // increment()에 synchronized를 사용하면 해결할 수 있음
        thread1.start();
        thread2.start();
        thread3.start();

    }
}

 

public class ServerAdvanced {
    public static void main(String[] args) {
        List<Student> studentList = new ArrayList<>(); // 고객 대기 리스트

        try (ServerSocket serverSocket = new ServerSocket(5000); // 서버 소켓 생성
        ) {
            System.out.println("Thread : " + Thread.currentThread().getName() + " is running");
            System.out.println("서버가 시작되었습니다.");

            while (true) {
                try {
                    Socket clientSocket = serverSocket.accept(); // 클라이언트 접속 대기
                    Thread request = new Thread(new RequestHandler(clientSocket, studentList));
                    request.start();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}