1. Introduction
1.1 멀티쓰레딩이란?
- 멀티쓰레딩 = 멀티프로세싱
- 멀티 프로세싱 운영체제는 동시에 여러개의 프로세스를 실행시킨다
- 각 프로세스는 자신만의 주소 및 메모리 공간을 갖는다.
- 운영체제 스케줄러는 어떤 프로세스를 실행시킬지 결정하는데 한번에 오직 하나의 프로세스만 실행가능하다.
- 그런데 시스템이 동시에 여러 프로세스가 실행되는 것'처럼' 보이게 하는 것
- 멀티쓰레드 애플리케이션은 동일한 메모리 공간 내에서 여러 개를 실행 포인트가 있다.
- 각 테스크들이 분리된 쓰레드로 동작함
- 하나의 쓰레드가 오래걸리는 것이 전체 애플리케이션이 그 쓰레드 하나를 끝낼때까지 기다리게 하지 않음
- 싱글쓰레드 애플리케이션에서는 하나의 실행 쓰레드가 모든 것을 해야 한다.
- 메인 메소드 있는 클래스에서 모든 것을 run!
- 모든 것을 순차적으로 진행하는데 특정 테스크 하나가 느리면 시스템 전체가 느리다고 느껴짐
2. Defining and Starting a Thread in Java
- 쓰레드의 인스턴스를 생성하는 애플리케이션은 반드시 해당 쓰레드가 실행되는 코드를 제공해야 한다
- 방식 1) 쓰레드 클래스 subclassing -> 서브 클래스에서 새로운 객체 만들기 (extends Thread)
- 방식 2) Runnable interface 구현 (implements Runnable)
- 위의 모든 방식은 run() 메소드를 구현해야 함
2.1 Examples
import java.util.Arrays;
public class Example1 {
public static void main(String[] args) {
Thread mainThread = Thread.currentThread();
System.out.println(mainThread);
runableTask1 object1 = new runableTask1();
runableTask2 object2 = new runableTask2();
// 쓰레드 이름 설정 가능 new Thread(.., .., 쓰레드 이름);
// 생성한 객체를 두번째 인자로 전달하는 방식
Thread thread1 = new Thread(mainThread.getThreadGroup(),object1,"Thread1");
// 객체 생성자체를 파라미터에서
Thread thread2 = new Thread(mainThread.getThreadGroup(),new runableTask2(),"Thread2");
// 객체 생성 함수도 여기서 작성 가능
Thread thread3 = new Thread(mainThread.getThreadGroup(),new Runnable() {
@Override
public void run() {
System.out.println("Task3");
}
} ,"Thread3");
// 쓰레드 객체 만들고 쓰레드 실행시키는 코드 반드시 필요
thread1.start();
thread2.start();
thread3.start();
mainThread.getThreadGroup().list();
}
}
class runableTask1 implements Runnable{
@Override
public void run() {
// the task your thread will do
int [] array = new int [100];
for (int i = 0 ; i<100;i++) {
array[i]=i;
}
try {
// 쓰레드 잠시 block 상태로 만드는 메소드 sleep()
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Arrays.toString(array));
}
}
class runableTask2 implements Runnable{
@Override
public void run() {
// the task your thread will do
System.out.println("Task2");
}
}
public class example2 {
public static void main(String[] args) {
task1 object = new task1();
object.start();
}
}
class task1 extends Thread {
@Override
public void run() {
System.out.print("Task1");
}
}
- runnable 인터페이스를 구현해서 쓰레드 만드는 방식이 더 흔하게 사용됨 (첫번째 예시)
3. Thread States
- 쓰레드 상태 : created, running, blocked, dead
- sleep() 메소드로 쓰레드 block 가능, 잠시 해당 쓰레드 실행 멈춤
- example
public class Racer implements Runnable {
public String winner;
// 생성자
public void race(){
}
private boolean isRaceWon(int totalDistanceCovered){
boolean isRaceWon = false;
if((winner==null )&&(totalDistanceCovered==100)){
String winnerName = Thread.currentThread().getName();
winner = winnerName; //setting the winner name
System.out.println("Winner is :"+winner);
isRaceWon = true;
}else if(winner==null){
isRaceWon = false;
}else if(winner!=null){
isRaceWon = true;
}
return isRaceWon;
}
@Override
public void run() {
for(int distance=1;distance<=100;distance++){
boolean isRaceWon = this.isRaceWon(distance);
// 누군가 win하면 isRaceWon 값이 true 로 바뀌어 반목분 break
if(isRaceWon){
break;
}
System.out.println("Distance Covered by "+
Thread.currentThread().getName()+ " is:"+distance +"meters");
//Check if race is complete if some one has already won
}
}
}
public class RaceDemo {
public static void main(String[] args) {
Racer racer = new Racer();
Thread tortoiseThread = new Thread(racer, "Tortoise");
// 아래 코드로 Tortoise 쓰레드에 우선순위를 최상으로 하면 항상 이 스레드가 win! - 치팅 코드!
tortoiseThread.setPriority(Thread.MAX_PRIORITY); // MIN으로 하면 getPriority = 1 MAX = 10
// 쓰레드 이름 바꾸기
tortiseThread.setName("Seungyoon");
System.out.println(tortoiseThread.getPriority()); // normal = 5 (우선순위 set 안하면 5 가 디폴트)
Thread hareThread = new Thread(racer, "Hare");
//Race to start. tell threads to start
tortoiseThread.start();
hareThread.start();
}
}
4. Thread property access methods
5. State transition methods for Thread
6. Thread synchronization
- 멀티쓰레드 -> 동일 메모리에 대한 동시 접근 발생 -> Memory consistency error 발생 가능
- 여러 개의 쓰레드가 하나의 변수에 동시에 접근하면 해당 변수가 저장되어 있는 메모리는 어떤 값을 최종 값으로 저장해야 하는지 혼란스럽다.
- 이를 해결하기 위해 동기화 필요 -> Synchronized solution
- example
- 같은 변수에 접근하는 모든 쓰레드들은 동시에 실행될 수 없게 하는 것 synchronized 키워드 !!
- 한 쓰레드의 작업 마친 후에 다음 쓰레드가 랜덤으로 실행 됨
class Counter{
int count;
// incre()에 대해 sychronized 키워드를 붙이면 t1 t2를 동시에 실행시켜도 결과가 일관되게 나옴
public synchronized void incr(){count++;}
}
public class Main {
public static void main(String[] args)throws InterruptedException {
Counter c = new Counter();
Thread t1 = new Thread(new Runnable(){
public void run(){
for(int i=0; i<1000; i++)
c.incr();
}
});
Thread t2 = new Thread(new Runnable(){
public void run(){
for(int i=0; i<1000; i++)
c.incr();
}
});
// 이렇게 두개를 동시에 실행시키면
// c에 대한 값에 두 쓰레드가 동시에 접근해서 매번 다른 값이 결과로 나오게 됨
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Count = " + c.count);
}
}
- Thread - wait() 메소드
- block thread
- 쓰레드 실행을 기다리게 하는 것
- Thread - notify() 메소드
- block 상태로 wait 기다리고 있는 쓰레드 랜덤으로 선택해서 깨우는 것
7. Thread Groups
public class example3 {
public static void main(String[] args) {
ThreadGroup threadGroup = new ThreadGroup("Network Threads");
Thread t1 = new Thread(threadGroup, new Runnable() {
@Override
public void run() {
System.out.println("network task1");
}
});
Thread t2 = new Thread(threadGroup, new Runnable() {
@Override
public void run() {
System.out.println("network task2");
}
});
t1.start();
t2.start();
//stop all threads of the network
threadGroup.interrupt();
threadGroup.list();
}
}
- Thread.currentThread() : 현재 실행 중인 쓰레드 반환
8. Threading in Swing
- swingworker 메소드 예시
References
- 성균관대학교 소프트웨어학과 타메르 교수님 <자바 프로그래밍 실습>
'프로그래밍 언어 > Java' 카테고리의 다른 글
Week12) Java Programming Lab : Generic Collections (0) | 2021.05.12 |
---|---|
Week11) Java Programming Lab : File I/O (0) | 2021.05.05 |
Week9) Java Programming Lab : Exception Handling (0) | 2021.04.19 |
Week8) Java Programming Lab : More on Grapical User Interface (GUI) (0) | 2021.04.12 |
Week7) Java Programming Lab : Grapical User Interface (GUI) AWT and Swing APIs (0) | 2021.04.05 |