21.09.17 - 웹 개발 입문 28일차
- 27일차 과제 풀이
Client 접속 시 "로또 번호 6개"를 Client에게 전송하는 서버
= 로또 번호 6개의 자료형은 다음과 같이 분석해볼 수 있다.
-> int 6개 : 멀티바이트 출력
-> int[] 1개 : 객체 출력
-> List<Integer> 1개 : 객체 출력
-> Set<Integer> 1개 : 객체 출력
-> 내가 만든 클래스 : 객체 출력
- 멀티 바이트로 구현
package api.net.tcp04;
import java.io.BufferedOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Random;
import java.util.Set;
import java.util.TreeSet;
public class Server4 {
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(30000);// 서버 30000포트 개방
Socket socket = server.accept();// 사용자 접속 수락
// 로또 번호 6개 추첨
Random r = new Random();
Set<Integer> lotto = new TreeSet<>();
while (lotto.size() < 6) {
lotto.add(r.nextInt(45) + 1);
}
// 사용자에게 로또번호 6개를 보내는 코드
// --> int 6개를 보낼 수 있도록 멀티바이트 스트림을 구성
OutputStream out = socket.getOutputStream();
BufferedOutputStream buffer = new BufferedOutputStream(out);
DataOutputStream data = new DataOutputStream(buffer);
for (int number : lotto) {
data.writeInt(number);
// data.flush();//그때그때 바로 전송
}
data.flush();// 끝나고 한번에 전송
socket.close();
server.close();
}
}
- 객체로 구현
package api.net.tcp04;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Random;
import java.util.Set;
import java.util.TreeSet;
public class Server5 {
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(30000);// 서버 30000포트 개방
Socket socket = server.accept();// 사용자 접속 수락
// 로또 번호 6개 추첨
Random r = new Random();
Set<Integer> lotto = new TreeSet<>();
while (lotto.size() < 6) {
lotto.add(r.nextInt(45) + 1);
}
// 사용자에게 로또번호 6개를 보내는 코드
// --> Set<Integer> 1개를 전송하도록 객체스트림을 구성
OutputStream out = socket.getOutputStream();
BufferedOutputStream buffer = new BufferedOutputStream(out);
ObjectOutputStream oData = new ObjectOutputStream(buffer);
oData.writeObject(lotto);
socket.close();
server.close();
}
}
서버에서 전송되는 데이터(로또번호 6개)를 수신하여 출력
= 서버에서 보내는 형태에 맞게 수신을 해야 한다.
--> 서버에서 멀티바이트로 전송하면 멀티바이트 수신을 해야한다
--> 서버에서 객체로 전송하면 객체 수신을 해야한다
package api.net.tcp04;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.net.UnknownHostException;
public class Client3 {
public static void main(String[] args) throws UnknownHostException, IOException {
Socket socket = new Socket("localhost", 30000);
// 서버에서 전송되는 데이터(로또번호 6개)를 수신하여 출력
// = 멀티바이트 수신코드
InputStream in = socket.getInputStream();
BufferedInputStream buffer = new BufferedInputStream(in);
DataInputStream data = new DataInputStream(buffer);
try {
while (true) {
int number = data.readInt();
System.out.println("로또번호 : " + number);
}
} catch (EOFException e) {
System.out.println("읽기 완료");
}
socket.close();
}
}
네트워크 - 문자열 데이터 전송
- 발신을 위한 스트림 구성
package api.net.tcp05;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(30000);
Socket socket = server.accept();
//데이터 준비
String str = "어서와 Java는 처음이지";
//출력스트림 준비
//= socket에는 outputstream/inputstream밖에 없다
//= writer/reader 계열을 사용하고 싶다면 "변환"이 필요
//= 이 역할을 수행하는 클래스가 OutputStreamWriter/InputStreamReader
OutputStream out = socket.getOutputStream();
OutputStreamWriter converter = new OutputStreamWriter(out);
BufferedWriter buffer = new BufferedWriter(converter);
PrintWriter printer = new PrintWriter(buffer);
printer.println(str);
printer.flush();
System.out.println("전송 완료");
socket.close();
server.close();
}
}
- 수신을 위한 스트림 구성
package api.net.tcp05;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;
public class Client {
public static void main(String[] args) throws UnknownHostException, IOException {
Socket socket = new Socket("localhost", 30000);
// InputStream in = socket.getInputStream();
// InputStreamReader converter = new InputStreamReader(in);
// BufferedReader buffer = new BufferedReader(converter);
// InputStreamReader converter = new InputStreamReader(socket.getInputStream());
// BufferedReader buffer = new BufferedReader(converter);
BufferedReader buffer = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String str = buffer.readLine();
System.out.println("str = " + str);
socket.close();
}
}
네트워크 - 문자열 전송 프로그램
Q. TCP 통신을 이용하여 클라이언트가 서버에 접속하도록 구현하시고 다음 요구사항에 맞게 코드를 구현하세요
- 클라이언트에서는 `Scanner`를 이용하여 사용자가 메세지를 입력합니다.
- 입력한 메세지는 socket을 이용하여 서버에 전송됩니다.
- 서버에서는 수신한 메세지를 화면에 출력합니다.
- 만약 클라이언트에서 사용자가 `종료`를 입력하면 더이상의 전송을 중지하고 연결을 종료합니다.
- 출력
package api.net.tcp06;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
public class Server3 {
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(30000);
Socket socket = server.accept();
// 사용자가 지속적으로 보내는 문자열 데이터를 받아서 출력하는 코드
InputStream in = socket.getInputStream();
InputStreamReader converter = new InputStreamReader(in);
BufferedReader buffer = new BufferedReader(converter);
while (true) {
String line = buffer.readLine();
if (line.equals("종료"))
break;
System.out.println("수신 : " + line);
}
socket.close();
server.close();
}
}
- 입력
package api.net.tcp06;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
public class Client3 {
public static void main(String[] args) throws UnknownHostException, IOException {
Socket socket = new Socket("localhost", 30000);
// 키보드 입력도구
Scanner sc = new Scanner(System.in);
// 네트워크 출력스트림
OutputStream out = socket.getOutputStream();
OutputStreamWriter converter = new OutputStreamWriter(out);
BufferedWriter buffer = new BufferedWriter(converter);
PrintWriter printer = new PrintWriter(buffer);
while (true) {
System.out.print("입력 : ");
String line = sc.nextLine();
printer.println(line);
printer.flush();
if (line.equals("종료"))
break;
}
sc.close();
socket.close();
}
}
입력 : 자바
입력 : 헬로우
입력 : 종료
수신 : 자바
수신 : 헬로우
네트워크 - 문자열 에코서버
목표 : 에코 서버(Echo server). 사용자가 보낸 메세지를 그대로 반환하는 서버
수신(입력)과 발신(출력)을 위한 스트림을 모두 준비해야 한다.
= 수신후 바로 전송이 가능
- 서버
package api.net.tcp07;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(30000);
Socket socket = server.accept();
// 수신용 스트림
InputStream in = socket.getInputStream();
InputStreamReader inConverter = new InputStreamReader(in);
BufferedReader inBuffer = new BufferedReader(inConverter);
// 발신용 스트림
OutputStream out = socket.getOutputStream();
OutputStreamWriter outConverter = new OutputStreamWriter(out);
BufferedWriter outBuffer = new BufferedWriter(outConverter);
PrintWriter printer = new PrintWriter(outBuffer);
// 메세지 수신 후 바로 발신
String line = inBuffer.readLine();
printer.println(line);
printer.flush();
socket.close();
server.close();
}
}
- 사용자
package api.net.tcp07;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
public class Client {
public static void main(String[] args) throws UnknownHostException, IOException {
Socket socket = new Socket("localhost", 30000);
// 수신용 스트림
InputStream in = socket.getInputStream();
InputStreamReader inConverter = new InputStreamReader(in);
BufferedReader inBuffer = new BufferedReader(inConverter);
// 발신용 스트림
OutputStream out = socket.getOutputStream();
OutputStreamWriter outConverter = new OutputStreamWriter(out);
BufferedWriter outBuffer = new BufferedWriter(outConverter);
PrintWriter printer = new PrintWriter(outBuffer);
String text = "Hello Java!";
printer.println(text);
printer.flush();
String line = inBuffer.readLine();
System.out.println("회신 : " + line);
socket.close();
}
}
회신 : Hello Java!
Q. 다음 요구사항에 맞게 `챗봇 서버`와 `챗봇 클라이언트`를 구현하시기 바랍니다
- 챗봇 서버(ChatbotServer) 클래스
- 1개의 클라이언트 접속을 받아 지속적으로 채팅에 답변을 하도록 구현
- 질문에 대한 답변은 다음 내용만 가능
- 질문 : $동기부여, 답변 : 넌 언제가 지구최강의 개발자가 될거야!
- 질문 : $링크, 답변 : 문서 사이트는 https://hiphop5782.github.io 입니다.
- 질문 : $화이팅, 답변 : 우리모두 화이팅!
- 질문과 일치하지 않는 채팅은 답변이 없는 것으로 간주하여 "답변이 준비되지 않았습니다" 전송
- 사용자에게서 `exit`라는 메세지가 수신될 경우 사용자의 연결을 종료
- 챗봇 클라이언트(ChatbotClient) 클래스
- 서버에 접속한 뒤 사용자의 채팅을 입력받아 서버로 전송한 뒤 답변을 수신하여 화면에 출력하도록 구현
- 사용자가 `exit`를 입력할 경우 서버로 종료메세지를 전송한 뒤 프로그램 종료
- 서버 구현 방법 (1) - 기본
package api.net.tcp08;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class ChatbotServer {
public static void main(String[] args) throws IOException {
// 서버 준비
ServerSocket server = new ServerSocket(30000);
// 사용자 접속
Socket socket = server.accept();
// 입력 및 출력 스트림 생성
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter printer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())));
while(true) {
//사용자 메세지 수신
String line = reader.readLine();
//사용자가 강제로 종료하면 line == null 수신
if(line == null || line.equals("exit")) {
break;
}
// printer.println(line);
switch(line) {
case "$동기부여": printer.println("넌 언젠가 지구최강의 개발자가 될거야!"); break;
case "$화이팅": printer.println("우리모두 화이팅!"); break;
case "$링크": printer.println("https://www.naver.com/"); break;
default: printer.println("지원하지 않는 명령입니다"); break;
}
printer.flush();
}
// 사용자 접속 종료
socket.close();
// 서버 종료
server.close();
}
}
- 서버 구현 방법 (2) - 출력 구문 통일
package api.net.tcp08;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class ChatbotServer2 {
public static void main(String[] args) throws IOException {
// 서버 준비
ServerSocket server = new ServerSocket(30000);
// 사용자 접속
Socket socket = server.accept();
// 입력 및 출력 스트림 생성
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter printer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())));
while(true) {
//사용자 메세지 수신
String line = reader.readLine();
//사용자가 강제로 종료하면 line == null 수신
if(line == null || line.equals("exit")) {
break;
}
String text;
switch(line) {
case "$동기부여": text = "넌 언젠가 지구최강의 개발자가 될거야!"; break;
case "$화이팅": text = "우리모두 화이팅!"; break;
case "$링크": text = "문서 사이트는 https://www.naver.com/ 입니다"; break;
default: text = "지원하지 않는 명령입니다"; break;
}
printer.println(text);
printer.flush();
}
// 사용자 접속 종료
socket.close();
// 서버 종료
server.close();
}
}
- 서버 구현 방법 (3) - 메세지별 응답을 Collection으로 정의한다.
package api.net.tcp08;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
public class ChatbotServer3 {
public static void main(String[] args) throws IOException {
Map<String, String> messages = new HashMap<>();
messages.put("$화이팅", "우리모두 화이팅!");
messages.put("$동기부여", "넌 언젠가 지구최강의 개발자가 될거야!");
messages.put("$링크", "문서 사이트는 https://www.naver.com 입니다");
// 서버 준비
ServerSocket server = new ServerSocket(30000);
// 사용자 접속
Socket socket = server.accept();
// 입력 및 출력 스트림 생성
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter printer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())));
while(true) {
//사용자 메세지 수신
String line = reader.readLine();
//사용자가 강제로 종료하면 line == null 수신
if(line == null || line.equals("exit")) {
break;
}
//명령에 대한 응답을 messages에서 찾는다(없으면 null이 나온다)
String text = messages.get(line);
if(text == null) {
printer.println("지원하지 않는 명령입니다");
}
else {
printer.println(text);
}
printer.flush();
}
// 사용자 접속 종료
socket.close();
// 서버 종료
server.close();
}
}
- 사용자
package api.net.tcp08;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
public class ChatbotClient {
public static void main(String[] args) throws IOException{
// 연결 생성
Socket socket = new Socket("localhost", 30000);
// 입력 및 출력 스트림 생성
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter printer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())));
Scanner sc = new Scanner(System.in);
while(true) {
System.out.print("명령 : ");
String input = sc.nextLine();//키보드 입력
printer.println(input);//메세지 출력
printer.flush();
if(input.equals("exit")) break;//exit 입력 시 서버에게 알린 후 응답 수신하지 말고 종료
String response = reader.readLine();//응답 수신
System.out.println("<서버응답>");
System.out.println(response);
}
sc.close();
// 연결 종료
socket.close();
}
}
명령 : 안녕
<서버응답>
지원하지 않는 명령입니다
명령 : $링크
<서버응답>
문서 사이트는 https://www.naver.com/
명령 : exit
- 추가
명령을 이용하여 응답을 생성하는 메소드로 구현하기 (CommandFactrory)
package api.net.tcp08;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
public class ChatbotServer4 {
public static void main(String[] args) throws IOException {
// 서버 준비
ServerSocket server = new ServerSocket(30000);
// 사용자 접속
Socket socket = server.accept();
// 입력 및 출력 스트림 생성
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter printer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())));
while (true) {
// 사용자 메세지 수신
String line = reader.readLine();
// 사용자가 강제로 종료하면 line == null 수신
if (line == null || line.equals("exit")) {
break;
}
// 명령에 대한 응답을 CommandFactory에서 찾는다
String text = CommandFactory.create(line);
printer.println(text);
printer.flush();
}
// 사용자 접속 종료
socket.close();
// 서버 종료
server.close();
}
}
- CommandFactrory
package api.net.tcp08;
public class CommandFactory {
//명령을 이용하여 응답을 생성하는 메소드
public static String create(String command) {
switch(command) {
case "$동기부여": return "넌 언젠가 지구최강의 개발자가 될거야!";
case "$화이팅": return "우리모두 화이팅!";
case "$링크": return "문서 사이트는 https://www.naver.com/ 입니다";
default: return "지원하지 않는 명령입니다";
}
}
}
스레드
싱글 스레드 vs 멀티 스레드 (cf : 프로세스)
= 프로세스는 실행중인 프로그램을 의미한다.
= 즉, 프로그램을 실행하면 프로세스가 생성된다고 볼 수 있다.
= 스레드는 프로세스에서 여러 개의 작업을 동시에 실행하기 위해 생성하는 작업 수행 단위
= 프로세스가 회사면 스레드는 작업자와 같다.
= 프로세스에는 무조건 1개의 스레드가 존재하며, 필요하다면 더 생성할 수 있다.
= 싱글 스레드는 스레드가 한 개인 경우를 말하며, 멀티 스레드는 추가로 스레드를 생성한 경우를 말한다.
= 자바는 실행하면 main이라는 이름의 스레드가 기본적으로 생성된다.
= 스레드는 동시에 1개의 작업을 수행할 수 있다.
싱글 스레드에서 여러 개의 작업을 처리해보기
1. 사용자에게 입력창을 보여주고 입력을 받는 작업
2. 1초 간격으로 1부터 100까지 출력하는 작업
package api.thread;
import javax.swing.JOptionPane;
public class Test02 {
public static void main(String[] args) throws InterruptedException {
// 1
String input = JOptionPane.showInputDialog("메세지 입력");
System.out.println(input);
// 2
for (int i = 1; i <= 100; i++) {
System.out.println(i);
Thread.sleep(1000L);
}
}
}
--> 블럭킹으로 인해 1번 메세지 입력을 안하면 2번 작업을 안한다
멀티스레드
스레드를 하나 생성해서 main 과 병렬로 실행
= main에서 1부터 100까지 출력하는 코드를 실행
= 생성한 스레드에서 입력 코드를 실행
package api.thread;
import javax.swing.JOptionPane;
public class Test03 {
public static void main(String[] args) throws InterruptedException {
// 스레드(일꾼) 생성
// Thread t = new Thread();//이렇게 생성하면 뭘 해야하는지 알 수 없다.
Thread t = new Thread() {// 익명클래스를 만들어서 작업을 run메소드에 재정의한다.
@Override
public void run() {
// 2
for (int i = 1; i <= 100; i++) {
System.out.println(i);
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
// 스레드(일꾼) 구동
t.start();
// 1
String input = JOptionPane.showInputDialog("메세지 입력");
System.out.println(input);
}
}
--> main이 끝나도 생성한 스레드의 작업은 멈추지 않고 진행된다.
스레드의 문제점
= main이 끝났을 때 스레드를 종료할것인가 종료하지 않을 것인가 결정을 해야 한다.
= 스레드에게 작업을 지시하기 전에 미리 약속을 해놔야 한다.
= 한 번 일을 시작하면 강제로 중지시키기가 매우 어렵다.
-> 데몬 스레드 생성으로 해결
package api.thread;
import javax.swing.JOptionPane;
public class Test04 {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread() {// 익명클래스를 만들어서 작업을 run메소드에 재정의한다.
@Override
public void run() {
// 2
for (int i = 1; i <= 100; i++) {
System.out.println(i);
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
// 이 지점에서 스레드에 필요한 모든 설정을 완료해야 한다.
// = 구동을 시작하면 통제할 수 없기 때문
t.setDaemon(true);
// 스레드(일꾼) 구동
t.start();
// 1
String input = JOptionPane.showInputDialog("메세지 입력");
System.out.println(input);
}
}
데몬 스레드 설정(main에 완전한 종속이 이루어진다)
= 모든 스레드가 데몬인 경우에만 종속이 이루어진다
= 단 한 개라도 데몬 스레드가 아닌 스레드가 생성되었다면 모든 데몬 스레드가 작동하지 않는다.
= 다 데몬하든가 아니면 다 하지말든가 중간은 없다.
스레드를 생성하는 다른 방법
= Runnable 인터페이스의 객체를 만들어서 작업 내용을 보관
= Ruunable 인터페이스를 이용하여 Thread를 생성
package api.thread;
import javax.swing.JOptionPane;
public class Test05 {
public static void main(String[] args) throws InterruptedException {
Runnable r = new Runnable() {
@Override
public void run() {
// 2
for (int i = 1; i <= 100; i++) {
System.out.println(i);
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
Thread t = new Thread(r);
t.setDaemon(true);
// 스레드(일꾼) 구동
t.start();
// 1
String input = JOptionPane.showInputDialog("메세지 입력");
System.out.println(input);
}
}
- 함수형 인터페이스(@FunctionalInterface)는 람다(추론)식이 가능하다.
package api.thread;
import javax.swing.JOptionPane;
public class Test06 {
public static void main(String[] args) throws InterruptedException {
Runnable r = () -> {
// 2
for (int i = 1; i <= 100; i++) {
System.out.println(i);
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
Thread t = new Thread(r);
t.setDaemon(true);
// 스레드(일꾼) 구동
t.start();
// 1
String input = JOptionPane.showInputDialog("메세지 입력");
System.out.println(input);
}
}
Q. 다음 작업을 처리할 수 있도록 스레드 환경을 구성하시오.
작업1 : 5초에 한번씩 콘솔에 `------------------------------` 출력(5번)
작업2 : 3초에 한번씩 콘솔에 `Hello` 출력(10번)
작업3 : 2초에 한번씩 콘솔에 `Java` 출력(15번)
package api.thread;
public class Test07_1 {
public static void main(String[] args) {
// 작업1 - thread(t1)
Runnable r1 = () -> {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(5000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("-----------------");
}
};
Thread t1 = new Thread(r1);
t1.setDaemon(true);
t1.start();
// 작업2 - thread(t2)
Runnable r2 = () -> {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(3000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Hello");
}
};
Thread t2 = new Thread(r2);
t2.setDaemon(true);
t2.start();
// 작업3 - main thread
for (int i = 0; i < 15; i++) {
try {
Thread.sleep(2000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Java");
}
}
}
Java
Hello
Java
-----------------
Java
Hello
Java
Hello
-----------------
Java
Java
Hello
Java
-----------------
Hello
Java
Java
Hello
-----------------
Java
Hello
Java
Hello
Java
-----------------
Java
Hello
Java
Hello
Java