thread는 한번에 하나만 처리
동시에 하고싶다면 하나를 더 만들어서 실행시킨다.
2) 멀티스레드
3) 프로세스 여러개가 하나의 목적을 위해 실행 (네트워크 통신 필요)
멀티 스레드방식으로 네트워크 통신 -> Apache server
접속자 한명당 스레드가 배정됨.
온라인 게임서버, 증권서버, 은행서버에 필수적.
Apache Tomcat ? 아파치 서버 +servlet 엔진 (웹서버의 기능을 수행할 수 있는 기능 ) -->WAS (web application server)
thread는 한번에 하나밖에 실행할 수 없다.
package ex06.thread.thread00;
public class NoThread {
public static void study() throws InterruptedException {
for (int i = 0; i < 10; i++) {
System.out.println("나는 카페에서 공부를 한다");
Thread.sleep(500);
}
}
public static void music() throws InterruptedException {
for (int i = 0; i < 10; i++) {
System.out.println("나는 카페에서 음악을 듣는다");
Thread.sleep(500);
}
}
public static void main(String[] args) throws InterruptedException {
study();
music();
}
}
내용을 입력하세요.
동시에 하고싶으면 이런식으로 프로그래밍 할 수도 있지만 (하나로)
무조건 한번한번 왔다갔다 실행하게 됨.
package ex06.thread.thread01;
class Student {
public void music() {
System.out.println("나는 카페에서 음악을 듣는다");
}
public void study() {
System.out.println("나는 카페에서 공부를 한다");
}
}
class StudentWork{
public static void duringCaffe(Student st) throws InterruptedException {
for(int i=0;i<10*2;i++) {
st.study();
Thread.sleep(500);
st.music();
Thread.sleep(500);
}
}
}
public class NoThread {
public static void main(String[] args) throws InterruptedException {
StudentWork.duringCaffe(new Student());
}
}
스레드를 하나 더 만들어서 병행시키고 싶으면 이런식으로 코딩 .
병행이므로 번갈아가며 찍힐수도, 그렇지 않을 수도 있음
package ex06.thread.thread02;
class Study extends Thread {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("카페에서 공부를 한다");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Music extends Thread {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("카페에서 음악을 듣는다");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class ThreadEx {
public static void main(String[] args) {
Study study = new Study();
Music music = new Music();
study.start(); // 스레드 클래스의 메소드 start - 스레드 실행
music.start();
}
}
스레드를 만드는 또 하나의 방법 - 인터페이스 상속
package ex06.thread.thread03;
//Java는 클래스 다중상속은 안되고
//인터페이스 다중상속은 가능하다.
class InCaffe {
protected String name;
}
//이미 다른 클래스를 상속받은 클래스는
//Thread를 상속시킬 수 없으므로
//Runnable 인터페이스의 run()메서드를 구현하도록 한다.
class Study extends InCaffe implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("카페에서 공부를 한다");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Music extends InCaffe implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("카페에서 음악을 듣는다");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class ThreadEx {
public static void main(String[] args) {
Study study = new Study();
Music music = new Music();
Thread tStudy = new Thread(study); //thread의 매개변수로 객체를 넘긴다
Thread tMusic = new Thread(music);
tStudy.start();
tMusic.start();
}
}
아래처럼 처리하면 스레드들이 일을 끝내기도 전에 결과값을 출력해버려서 결과값이 제대로 나오지 않는다.
package ex06.thread.thread04;
class Sum implements Runnable {
int num = 0;
int start, end;
Sum(int start, int end) {
this.start = start;
this.end = end;
}
@Override
public void run() {
for (int i = start; i <= end; i++) {
num += i;
}
}
}
public class ThreadJoin {
public static void main(String[] args) {
Sum sum0 = new Sum(1, 50);
Sum sum1 = new Sum(51, 100);
// 객체 하나당 스레드 하나
Thread t0 = new Thread(sum0);
Thread t1 = new Thread(sum1);
t0.start();
t1.start();
System.out.println("1~100까지의 합 : " + (sum0.num + sum1.num));
// 값이 출력할때마다 다르게 나온다.
}
}
그래서 자식 스레드가 종료될 때 까지 대기해줘야한다. -->join()을 이용
t0.start();
t1.start();
//스레드는 독립적으로 처리되는 리소스이므로 main스레드와 자식스레드는 별개로 동작한다.
//자식 스레드가 종료될 때까지 대기
t0.join(); //sum0의 run()이 리턴되면 join()을 리턴
t1.join(); //sum1의 run()이 리턴되면 join()을 리턴
문제가 될 때 - 값이 간혹가다 잘못 나온다.
join메서드로 스레드의 계산을 기다렸는데도 불구하고 생긴 문제!
알바생 두명이 하나가지고(static int num) 일을 하니까 일이 제대로 안된 것.
자기 일도 안끝났는데 쟤가 써버리니까..
그래서 동기화가 필요하다.
package ex06.thread.thread05;
class Sum implements Runnable {
static int num = 0; //static 변수는 class에 1개만 존재, 모든 객체가 공유
int start, end;
Sum(int start, int end) {
this.start = start;
this.end = end;
}
@Override
public void run() {
//아래의 num은 모든 객체가 공유하므로
//Context Switching시 변수의 값이 왜곡될 수 있다.
//그러므로 왜곡되지 않도록 하는 처리가 필요하다.
//이를 스레드(값의) 동기화라고 한다.
for (int i = start; i <= end; i++) {
num += i;
}
}
}
public class NoSyncThread {
public static void main(String[] args) throws InterruptedException {
Sum sum0 = new Sum(1, 50);
Sum sum1 = new Sum(51, 100);
// 객체 하나당 스레드 하나
Thread t0 = new Thread(sum0);
Thread t1 = new Thread(sum1);
t0.start();
t1.start();
//스레드는 독립적으로 처리되는 리소스이므로 main스레드와 자식스레드는 별개로 동작한다.
//자식 스레드가 종료될 때까지 대기
t0.join(); //sum0의 run()이 리턴되면 join()을 리턴
t1.join(); //sum1의 run()이 리턴되면 join()을 리턴
System.out.println("1~100까지의 합 : " + Sum.num);
}
}
공유 변수를 사용할 때 스레드의 문제점.