210423_3~4(멀티스레드)
멀티스레드
1. 스레드 Thread : 어떤 로직이나 함수의 실행 단위.
a(){ }
(cpu자원)
a( ) 3번 호출 |---a()---|---a()---|---a()---| ===> 단일스레드 - 지금까지 사용법
각각의 함수가 자원을 독점
(cpu자원)
a( ) 3번 호출 |---a()---|
|---a()---|
|---a()---|
-- 동시성을 갖고 실행되는구간===> 멀티스레드(동시에 실행되는 것처럼 보임)
자원을 공유해서 사용한다
멀티스레드의 장점
[웹서버 - 하나의 클라이언트 처리시간 1초라고 가정]
동시에 1000명이 접속했다. 1000번째 사람의 앞에 999명의 즉999초 동안 기다려야 자신의 처리가 돌아온다
그런데, 멀티스레드가 되면, 웹서버가 자원을 돌아가면서 모든 클라이언트들에게 처리를 조금씩 돌아가면서
하게되므로 훨씬 빠른속도로 자신의 처리를 할 수가 있다.
돈이 되는 프로그램은 다 멀티다. 게임서버, db서버, 웹서버, 채팅 서버 ...~
적용방법
Runnable 인터페이스 적용하거나
|
Thread 클래스를 상속받아서 // Thread클래스는 Runnable을 구현한 구현 클래스이다.
|
MyThread { // 다중상속으로 Thread상속을 받을수없을때 Runnable 인터페이스를 적용한다.
↓
run( ) {
멀티로 구현하고자 하는 로직이나 함수를 run 메서드로 감싼다
}
}
기억!
Runnable | Thread |
run() | run(), start()가 있다. |
결론 : 실행하려면 start() 가 포함하는 Thread 객체(인스턴스)를 만들어야한다
호출
MyThread mt = new MyThread ();
mt.run() ; <=== 호출불가. run()은 구현만 할 수 있고, 호출이 불가하다. 그래도 호출하면 단일스레드로 작동됨(주의
mt.start() ; <=== start() 라는 메서드로 호출한다.
원리
start( ) <==== jvm에 요청 등록 === >run() 호출
run( ) 은 jvm에 의해서 호출되므로 callback method라고 한다.
package chapter16;
//스레드가 없는경우
class GenClass {
private int num; //필드1
private String name; //필드2
public GenClass(String a, int b) { //생성자
name = a;
num = b;
}
public void start() { //메서드1
for (int i = 0; i < num; i++) //로직
System.out.println(name + "." + i);
}
}
public class NonThread {
public static void main(String[] args) {
GenClass t1 = new GenClass("first", 5);
GenClass t2 = new GenClass("second", 5);
GenClass t3 = new GenClass("third", 5);
t1.start(); //단일스레드 jvm start()와 관련x
t2.start();
t3.start();
}
}
//first.0
//first.1
//first.2
//first.3
//first.4
//second.0
//second.1
//second.2
//second.3
//second.4
//third.0
//third.1
//third.2
//third.3
//third.4
package chapter16;
//멀티스레드 적용
class MyThread extends Thread { //스레드상속
private int num;
private String name;
public MyThread(String a, int b) { //생성자
name = a;
num = b;
}
public void run() { // 멀티스레드구현 run()메서드
for (int i = 0; i < num; i++)
System.out.println(name + ":" + i);
}
}
public class ThreadTest1 {
public static void main(String[] args) {
MyThread t1 = new MyThread("first", 1000); //인스턴스1
MyThread t2 = new MyThread("second", 1000); //인스턴스2
MyThread t3 = new MyThread("third", 1000); //인스턴스3
t1.start(); // jvm start
t2.start(); // 단 한번이라도 처리가 섞이면 멀티스레드이다
t3.start();
}
}
//second:0
//third:0
//first:0
//third:1
//second:1
//third:2
//first:1
//third:3
//second:2
//third:4
//....~~
package chapter16;
//Runnable 인터페이스를 통한 멀티스레드
class ThreadOne implements Runnable { // Runnable 인터페이스상속//ThreadOne가 Runnable을 적용한 타겟클래스이다
private int num;
private String name;
public ThreadOne(String a, int b) {
name = a;
num = b;
}
public void run() { // 멀티스레드 구현
for (int i = 0; i < num; i++)
System.out.println(name + ":" + i);
}
}
public class TreadTest2 {
public static void main(String[] args) {
Thread t1 = new Thread(new ThreadOne(("first"), 1000));
// Thread는 Runnable을 구현한 클래스이다
// Runnable로 만들면 하위객체를 호출하지못하기때문에 형변환도해야한다
Thread t2 = new Thread(new ThreadOne(("second"), 1000));
Thread t3 = new Thread(new ThreadOne(("third"), 1000));
//생성자안의 파라미터에 Runnable의 인자(상속받은 ThreadOne)를 넣어서 사용하기때문
// =new Tread(new 러너블타겟()) ->new 러너블타겟()이 인자를 두개갖고있기때문에()가 또들어간것
t1.start();
t2.start();
t3.start();
}
}
동시성 구간을 크게하기
앞의 사실에서 알수있듯이, 첫 스레드에서 잠시 쉬어갈때 다른 스레드가 시작된다.
그렇다면, 강제로 쉬게 하면 더 동시성 구간이 커지지 않을까?
그래서 sleep(ms);메서드 ms는 1/1000초 동안 쉬도록 하면 골고루 섞인다.
package chapter16;
//동기화없는 경우
class RunThread extends Thread {
public RunThread(String name) {
super(name); //Thread의 String을 인자로 갖는 생성자
}
public void run() {
for (int i = 1; i <= 500; i++) {
if (i % 50 == 0)
System.out.println("Thread[" + getName() + "]:" + i);
//getName은 상속받은 Thread에서 온것
}
}
}
public class SchedulingTest1 {
public static void main(String[] args) {
Thread[] t = new RunThread[2]; //스레드 배열
t[0] = new RunThread("ONE");
t[1] = new RunThread("TWO");
t[0].start();
t[1].start();
}
}
//Thread[TWO]:50
//Thread[TWO]:100
//Thread[TWO]:150
//Thread[ONE]:50
//Thread[ONE]:100
//Thread[TWO]:200
//Thread[ONE]:150
//Thread[ONE]:200
//Thread[TWO]:250
//Thread[ONE]:250
//Thread[TWO]:300
//...~ 동시성이거의없다
package chapter16;
//동기화를 처리한경우
class RunThread2 extends Thread {
public RunThread2(String name) {
super(name);
}
public void run() {
for (int i = 1; i <= 500; i++) {
if (i % 50 == 0) {
System.out.println("Thread[" + getName() + "] :" + i);
try {
sleep(1); // 1/1000초에 한번 쉼 //동시성을 크게하기위함
System.out.println("");
} catch (Exception e) {
}
}
}
}
}
public class SchedulingTest2 {
public static void main(String[] args) {
Thread[] t = new RunThread2[3];
t[0] = new RunThread2("☆");
t[1] = new RunThread2("★");
t[2] = new RunThread2("◆");
t[0].start();
t[1].start();
t[2].start();
}
}
//Thread[★] :50
//Thread[☆] :50
//Thread[◆] :50
// //sleep발생구간
//
//Thread[☆] :100
//
//Thread[★] :100
//Thread[◆] :100
//Thread[★] :150
//
//
//Thread[◆] :150
//Thread[☆] :150
//
//
//
//Thread[◆] :200
//Thread[★] :200
//Thread[☆] :200
//
//
//Thread[★] :250
//
//Thread[◆] :250
//Thread[☆] :250
//...~