오늘은 Thread에 대해서
주로 공부할 것이다.
목차
1. Thread
2. Runnable
3. 익명클래스
4. 동기화
5. 스레드의 기능들
1. Thread
Thread - 작성된 코드를 실행하는 객체 - 동시에 여러 작업을 하고 싶을 때 쓰는 문법
기본적으로 우리는 프로그래밍의 실행이
한 줄식 차례대로 되는 것으로 배웠다.
그렇다면 만약 파일을 다운로드하면서
음악 재생을 하고 싶을 땐 어떻게 해야 할까?
바로 오늘 배울 Thread를 이용해야 한다.
스레드는 작성된 코드를 실행하는 객체로
동시에 여러 작업을 처리할 수 있다.
이를 왜 쓰냐면
어떤 프로그램을 다운로드하는 것과 동시에
음악을 듣는 상황이라고 가정해 보자.
근데 동시에 처리를 하지 않는다면
다운로드가 다 끝날 때까지
유저는 음악을 들을 수 없는 상황이 발생한다.
그러기에 스레드를 통해서 여러 작업을 하게 하는 것이다.
만일 우리가 지금껏 배운 대로
2개의 작업을 구현한다면 위의 사진과 같이 적을 수 있다.
그러나 저렇게 적으면
한 작업이 끝나야 다음작업에 들어간다.
그래서 스레드라는 별도의 객체를 생성해서
각각의 코드를 실행하도록 요청해야 한다.
그러기 위해선 별도의 class를 설계해서
그 class가 해야 할 작업도
설계를 해야 한다.
기본적으로 Thread라는 클래스가 있는데
이를 상속받아 클래스를 만들면 된다.
그리고 상속을 받으면
기존 메서드를 오버라이드할 수 있다.
스레드에서 가장 중요한 메소드는
run()이라는 메소드이다.
그런데 정작 run()은 사용하지 않는다.
왜냐하면 run()을 사용하면
우리가 원하는 방향으로
실행되지 않는다.
즉 하나가 끝나야 하나가 실행되는 방식이 돼버린다.
그래서 start()라는 메소드를 사용해야 하며
이를 사용하면 run()이 발동하게 된다.
이 방법을 통해 실행하면
동시에 처리가 되고 있다는 것을 알 수 있다.
후에 안드로이드를 배우면서도 많이 공부할 부분이니
개념정도만 익혀가자!
2. Runnable
Thread 능력을 가지는 방법엔 2가지가 있다.
첫째론 아까 우리가 한 것과 같이 Thread클래스를 상속한
클래스를 설계하는 것이다.
두 번째 방법은 Runnable 인터페이스를 구현한 클래스를 설계하는 방법이다.
그럼 왜 굳이 방법이 여러 개일까?
대표적인 이유는 다중 상속의 효과를 누리기 위해서이다.
자바는 다중상속이 금지되어 있기에
인터페이스를 통해 구현하면 상속도 받을 수 있고
인터페이스를 통한 다중구현도 가능해진다.
위의 사진처럼 상속도 받으면서
Runnable 인터페이스를 구현한 클래스를 만들 수 있다.
(여기서 sleep은 스레드를 해당시간 동안 재우는 것으로
1000밀리 세컨드 즉, 한번 실행하고 1초 재우는 형태다.)
Runnable 인터페이스를 구현한 클래스는
start()를 사용할 수 없다.
그 이유는 Runnable 인터페이스에는 없는 메소드이기 때문이다.
그래서 별도의 Thread 객체를 만들고
() 안에 클래스명을 넣은 다음에
start();를 사용해줘야 한다.
다중상속이 필요할 때뿐만 아니라 스레드객체가 필요할 때도
Runnable로 만들기도 한다. (업캐스팅이 가능해서)
3. 익명클래스
그런데 매번 이름을 명명해야 하는 점도 그렇고
스레드를 확인하기 위해 아래까지 내려야 해서
어떤 동작을 수행할지 한눈에 보이지 않는 점이
불편해서
이를 보완하는 문법이 나오게 된다.
이 문법이 바로 익명클래스이다.
Runnable 부모 참조변수를 이용해 객체를 만들고
끝내는 것이 아니라 { }를 열어서
그 자리에 run() 메소드를 오버라이드 하는 방식이다.
4. 동기화
프로그래밍 언어에서 동기란
순서대로 하는 것이다.
즉 a작업이 끝나면 b작업을 하는 것이다.
그렇다면 비동기는
동시에 여러 일을 하는 것을 말한다.
그래서 사실 Thread는 비동기 처리를 의미한다.
하지만 Thread를 사용할 때도
분명 순서대로 해야 하는 상황이 발생한다.
(예를 들면 한 변수를 여러 스레드가 건드려서
원하는 값이 출력되지 않는 상황 등..)
이를 해결하기 위해 동기화처리를 하는 문법이 나타난 것이다.
위 사진과 같이 은행계좌 클래스가 있다고 해보자.
만일 별도의 동기화 처리를 하지 않는다면 서로 다른 스레드가 동시에
이 기능을 실행했을 때 문제가 발생할 수 있다.
그때 동기화를 사용할 수 있는데
방법은 두 가지이다.
첫째론 메소드를 동기화 처리하는 것이다.
그러나 이 방식을 이용하면
동시에 처리하는 방식이 아닌
하나 처리하고
하나마저 처리하는 방식이 된다.
두 번째 방법은 동기화 블록을 사용하는 것이다.
synchronized (this){ } 를 이용해서
동기화할 부분만 묶어주면 된다.
그럼 해당 부분을 실행할 땐
하나하나 실행되고
그 나머지 부분은 같이 실행시킬 수 있다.
5. 스레드의 기능들
스레드의 기능들 중 대표적인 몇 가지를 소개하려 한다.
우선 sleep은 위에서도 설명했듯
해당 시간만큼 잠시 기능을 멈추는 기능이다.
( ) 안에는 원하는 밀리세컨드를 입력해 주면 된다.
그리고 sleep()으로 자고 있는 스레드를
강제로 깨워 예외를 발생시키는 문법도 있다.
바로 interrupt();이다.
이 사진과 같은 클래스가 있다고 해보자.
그런데 스레드를 통해 실행한 것과
메인함수에서 적은 작업이 같이 돌아가는 것이 아니라
j 작업이 먼저 완료한 후에 작업하고 싶을 때 사용하는 문법이 join이다.
아까 동기화처리를 배웠지만 동기화 문법으로는 안될 때 사용하는 방법이다.
이렇게 생긴 클래스가 있다고 가정하자.
여기서 wait()은
sleep과는 달리 시간제한 없이
스레드의 동작을 멈추는 기능이다.
그러나 사용 시 동기화 문법을 꼭 사용해야 한다.(안 하면 에러)
그리고 객체지향에선
멤버변수를 함부로 만질 수 있는 것을 싫어한다.
따라서 일시정지 시킬 수 있는 메소드를 따로 만들어서
제어를 해주는 것이 좋다.
(boolean 값을 바꿔서 if문 발동!)
그리고 시간제한 없이 멈추는 기능이 있다면
다시 실행하는 기능 역시 있어야 한다.
이 기능이 바로 notify()이다.
이 또한 겹치면 에러가 날 수 있어서
wait()과 마찬가지로
동기화 문법을 사용해줘야 한다.
마지막으로
위의 클래스의 while문의 조건을 거짓으로 바꾸는 메소드에 대한 설명이다.
스레드를 종료시키는 목적의 메소드인데
notify가 들어가 주는 것이 좋다고 한다....
'# 개발 > Java' 카테고리의 다른 글
Java #13 - protocol, network (국비25일차) (0) | 2023.02.06 |
---|---|
Java #12 - Stream, 바이트스트림, 문자스트림 (국비24일차) (0) | 2023.02.03 |
Java #10 -Generic, Collection API (국비22일차) (0) | 2023.02.01 |
Java #9 -오브젝트 클래스, 예외(Exception) (국비21일차) (0) | 2023.01.31 |
Java #8 - 다형성(polymorphism), 추상(abstract), 인터페이스 (국비20일차) (0) | 2023.01.30 |