티스토리 뷰

1.    채팅의 종류 :

-      (1) 1 : 1 채팅 : Unicast

-      (2) N : M 채팅 : Muticast

 

2.    채팅구현에 있어 ServerSocket의 단점 :

-      ServerSocket을 활용한 네트워킹을 할 경우, 모든 작업을 Main이라는 Thread가 모든 작업을 처리해야 하기 때문에 다른 작업을 동시에 할 수 없다.

-      그렇기에, 동시에 다양한 작업을 하기 위해 멀티 스레드를 사용한다.

 

3.    멀티 스레드 ( 12)

-      프로세스(process) : 실행 중인 하나의 프로그램을 의미하며, 하나의 프로그램이 다중 프로세스를 만들기도 한다. ( ex. 브라우저 )

-      멀티 프로세스 : 독립적으로 프로그램들을 실행하고, 여러 가지 작업을 처리한다.

-      멀티 태스킹[ (Muti-Tasking) : 동시에 여러 작업을 하는 것 ]을 위해서는 멀티 스레드나 멀티 프로세스를 구현해야 한다.

-      이때 스레드는 하나의 실행 흐름을 의미한다.

-      멀티 스레드 : 한 개의 프로그램을 실행하고, 내부적으로 여러 가지 작업을 처리

-       + 멀티 프로세스 : 다양한 프로세스, 멀티 스레드 : 하나의 프로세스 안의 2개 이상의 스레드

 

4.    Main 스레드

-      모든 자바 프로그램은 메인 스레드가 main( )메소드를 실행하면서 시작한다.

-      main( ) 메소드는 첫 코드부터 아래로 순차적으로 실행한다.

-      실행 종료 조건 : 1) 마지막 코드를 실행할 때 2) return문을 만났을 때

-      Main 스레드는 작업 스레드를 만들어서 병렬로 코드를 실행할 수 있음:멀티 스레드

-       + JVM의 스레드가 아닌, 개발자가 직접 생성하는 스레드를 “User-Thread”라고 일반적으로 호칭하며, “Worker Thread”라고 부르기도 한다.

-      프로세스의 종료 시점 :

-       1 ) 싱글 스레드 : 메인 스레드가 종료되면, 프로세스도 종료

-       2 ) 멀티 스레드 : 실행 중인 스레드가 1개라도 있다면, 프로세스 미종료

 

5.    Worker Thread 생성 방법

-      1 ) Thread 클래스로부터 직접 생성하는 방법

-       : Runnable을 매개값으로 갖는 생성자 호출

-      2 ) Thread 하위 클래스로부터 생성

-       : Thread 클래스 상속 후 run 메소드를 재정의 해서 스레드가 실행할 코드 작성

 

6.    TCP 기반의 네트워킹에 사용된 메소드 종류

-      1 ) accept ( )         2 ) read ( )       3 ) write ( )      4 ) connect ( )


더보기

01. 객체입출력를 통한 서버 구현 ( New 버전 )

package tcp_practice;

import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Arrays;

import lombok.extern.log4j.Log4j2;

@Log4j2
public class S08_ObjectServer {
	
	public static void main (String[] args) throws IOException { // 객체입출력으로 서버구현 ( new )
		
		// 객체의 직렬화와 역직렬화로 구현하게 되면, 좀 더 안정적으로 운영할 수 있다.
		
		log.debug("main({}) invoked.", Arrays.toString(args));
		
		int listenPort = 7777;
		int backLog = 100;
		
//		===========================================================================
		
		ServerSocket severSocket = new ServerSocket(listenPort,backLog);
		log.debug("1. severSocket", severSocket);
		
//		===========================================================================
		
		try(severSocket){
			
			while(true) { // 서버는 계속 주고 받고 해야 하기 때문에 무한루프
				
				log.info("------------------------------------------------------------------------------");
				log.info("2. Server Listening address : {}",severSocket.getLocalSocketAddress());
				log.info("------------------------------------------------------------------------------");
				
				Socket sock = severSocket.accept(); // Blocking IO
				
				log.info("3. Client connected from address : {}",sock.getRemoteSocketAddress());
				
				try(sock;){
					
//					===============================================================
					// RECV : 받을 준비
//					===============================================================
					
					InputStream is = sock.getInputStream();
					
					// 객체의 직렬화 / 역직렬화를 이용한 입력 / 출력을 위해 Object 기반의 입력 보조스트림 생성
					ObjectInputStream ois = new ObjectInputStream(is);
					
					// 객체를 읽어드림 ( 이때 readobject 메소드의 리턴 타입은 object이다. )
					// 따라서 리턴값이 다형성1에 의해서, 조상품에 안겨서 반환되기 때문에
					// 실제 객체의 역직렬화를 통해서 받은 객체를 강제형변환을 통해 부모의 품에서 빼내야 한다.
					
					Member member = (Member) ois.readObject();
					log.info("4. receive a member from client : {}",member);
					
					// 단, 이 경우에는 멤버 객체만을 주고 받을 수 있게 된다.
					
//					===============================================================
					// SENT : 보낼 준비
//					===============================================================
					
					OutputStream os = sock.getOutputStream();
					
					// 객체의 직렬화/ 역직렬화를 이용한 입/출력을 위해 Object 기반의 출력 보조스트림 생성
					ObjectOutputStream oos = new ObjectOutputStream(os);
					
					member.setId(2);
					member.setName("Trinty");
					member.setAge(33);
					
					oos.writeObject(member); // 전송
					oos.flush(); // 출력 스트림을 사용했기에, 강제 flush를 해야 한다.
					
					log.info("5. Sended a modified member to client : {}",member);
					
				} catch ( IOException | ClassNotFoundException e) {
					
					e.printStackTrace();
					
				}// try with : sock
				
			} // while
			
		} // try with :severSocket
		
	} //main

} // end class

더보기

02. 객체입출력을 통한 클라이언트 구현

package tcp_practice;

import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.Arrays;

import lombok.extern.log4j.Log4j2;

@Log4j2
public class S08_ObjectClient {
	
	public static void main (String[] args) throws IOException, ClassNotFoundException { // 객체입출력으로 클라이언트 구현 ( new )
		
		log.debug("main({}) invoked.", Arrays.toString(args));
		
		Member member = new Member();
		member.setId(0);
		member.setName("YOseph");
		member.setAge(23);
		
		String serverAddress = "localhost";
		int serverPort = 7777;
		int connectTimeout = 100*1; // milli
		
		
		Socket socket = new Socket();
		socket.connect(new InetSocketAddress(serverAddress,serverPort),connectTimeout);
		
		log.info("1. Connected to server, socket : {}", socket);
		
//		===========================================================================
		
		try(socket;){
			
			OutputStream os = socket.getOutputStream();
			ObjectOutputStream oos = new ObjectOutputStream(os);
			
			oos.writeObject(member);
			oos.flush();
			
			log.info("2. Sended a member to server : {}", member);
			
//			===========================================================================
			
			InputStream is = socket.getInputStream();
			ObjectInputStream ois = new ObjectInputStream(is);
			
			member = (Member) ois.readObject();
			log.info("3. Received a member from server : {}", member);
			
			
		} // try with ; socket

		
	} //main

} // end class

더보기

03. 멀티 스레드를 통한 서버 구현

package tcp_practice;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Arrays;

import lombok.extern.log4j.Log4j2;


@Log4j2
public class S09_MutiThreadSocketServer {
	
	private static final int port = 7777;
	
	public static void main(String[] args ) throws IOException {
		
		log.debug("main({}) invoked.", Arrays.toString(args));
		
		ServerSocket serverSock = new ServerSocket(port);
		
		try( serverSock;){ // severSock을 자동으로 닫게 해주고
			
			while(true) {
				
				log.info("Listenning on {} ......", serverSock);
				
				Socket sock = serverSock.accept(); // Blocking IO
				
				log.info("\t + Client connect from {}", sock);
				
//				====================================================
				
				// 데이터 수신 Task를 별도의 스레드에서 수행 - task1
				new Receiver01 ("Receiver01",sock).start();
//				new Receiver02 ("Receiver02",sock).start();
				
//				====================================================
				
				// 데이터 송신 Task를 별도의 스레드에서 수행 - task2
				new Sender01("Sender01",sock).start();
				
				// 데이터의 송신과 수신을 다른 스레드에서 시행해야지 멀티 태스킹이 가능하다!!(***)
				
//				====================================================
				
			} // while
				
		} // try - with - resource : serverSock
		
	} // main

} // end class

더보기

04. 멀티 스레드를 통한 클라이언트 구현

package tcp_practice;

import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.Arrays;

import lombok.extern.log4j.Log4j2;

@Log4j2
public class S09_MutiThreadSocketClient {
	
	private static final String host = "127.0.0.1"; // 서버의 주소
	private static final int port = 7777;
	
	public static void main (String[] args) {
		
		log.debug("main({}) invoked.", Arrays.toString(args) );
		
//		================================================================
		
		try {
			
			// 소켓 생성 및 연결 시도
			Socket sock = new Socket();
			sock.connect(new InetSocketAddress(host,port),1000); // 연결만료 시간 : 1초로 설정
			
			log.info("Connected to the server addr : {}, port : {}", host,port);
			
//			================================================================
			
//			new Sender07("Sender07",sock).start();
			new Sender07("Sender01",sock).start();
			
//			================================================================
			
			new Receiver01("Receiver01", sock).start();
			
//			================================================================
			
		} catch ( Exception e) { 
			e.printStackTrace();
		} // try - catch
		
//		================================================================
		
	} // main

} // end class

더보기

05. 멀티 스레드를 위한 데이터 수신 스레드

package tcp_practice;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;

import lombok.extern.log4j.Log4j2;

@Log4j2
public class Receiver01 extends Thread { // 데이터 수신 - Thread 클래스의 자식 클래스 형태로 선언
	
	private Socket sock; // ServerSocket
	private InputStream is; // InputStream
	
//	=================================================================
	
	public Receiver01(String threadName, Socket sock ) {
		
		log.debug("Constructor invoked.",sock);
		
		this.sock = sock;
		
		super.setName(threadName + "-" + super.getName());
		
		try {this.is = this.sock.getInputStream();}
		catch(IOException e) { ;; }
		
	} // Receiver01 constructor
	
//	=================================================================
	
	// 부모 클래스인 Thread가 물려준, run() 메소드를 재정의 :
	// 참고로 부모의 run() 메소드는 하는 일이 없다.
	// 이 run() 메소드의 블록 범위가 새로운 스레드의 실행범위가 된다.
	
//	=================================================================
	
	@Override
	public void run() {
		
		log.debug("run() invoked.");
		
		// 아래의 타입은 자바입출력을 위한 보조스트림 중 하나로
		// 바이트 단위의 데이터를 메모리에 보관할 수 있게 해주는 보조 출력 스트림이다.
		
		ByteArrayOutputStream baos = new ByteArrayOutputStream(); // (*****)
		
		try (baos;){ // 보조 스트림도 닫아줘야 한다.
			
			int ch; // char
			int CR = 13, LF = 10; // Enter Key code
			
			while( (ch = is.read()) != -1 ) { // 입력스트림 is의 EOF인 -1을 만날때 까지 반복 ( 상대편이 끊어야 -1이 들어온다. )
				
//				log.info("ch : {}", ch);
				
				if( (ch != CR) & (ch != LF ) ) { // 수신된 바이트 값이 CRLF가 아니면....
					baos.write(ch); // 보조스트림에 저장(****)
				} else {
					
//					log.info("\t + excleded : {}", ch);
					
					if ( ch == LF) { // 수신된 바이트 값이 CR 또는 LF라면 ( 엔터키를 쳤다면 )
						
						// 현재까지 보조출력스트림에 저장된 모든 바이트열을 문자열로 변환
						String recv = baos.toString("UTF-8"); // charset을 지정하여 바이트를 문자로 변환
						log.info("RECV : {}", recv); // 콘솔에 출력
						
						baos.reset(); // 바이트열 보조스트림 내부를 깨끗하게 지운다. (공장모드)
						
						// 출력하는 것이 아니라 자바버추얼머신 메모리에 박스를 만들어서 보관하는 것이기에, flush는 사용하지 않아도 된다.
						
					} // inner if
					
				}// if - else
	
			} // while
				
		} catch ( Exception e ) { ;; } // 예외처리할 것은 없다.
		finally {
			// 순서에 맞게 닫아줘야 한다.
			try {this.is.close();} catch (IOException e) { ;; } // 소켓 속에서 입력스트림을 얻었기에, 입력스트림을 먼저 닫고
			try {this.sock.close();} catch (IOException e) { ;; } // 소켓을 닫는다.
			
		} // try - catch - finally
		
		log.info("Done.");
		
	} // run()

} // end class

더보기

06. 멀티 스레드를 위한 데이터 송신 스레드 1

package tcp_practice;

import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;

import lombok.extern.log4j.Log4j2;


@Log4j2
public class Sender01 extends Thread {
	
//	===============================================
	
	private Socket sock; // ServerSocket
	private OutputStream os; // OutputStream
	
//	===============================================
	
	Sender01(String threadName, Socket sock ){
		
		log.debug("Constructor invoked.",sock);
		
		this.sock = sock;
		
		super.setName(threadName + "-" + super.getName());
		
		try {this.os = this.sock.getOutputStream();}
		catch(IOException e) { ;; }
		
	} // Sender01
	
//	===============================================
	
	@Override
	public void run() {
		
		log.debug("run() invoked.");
		
		try {
			
			int CR =13, LF =10;
			
			// HandShake Protocol 대로 메시지를 보낸다.
			for (int i=0; i<10; i++) {
				
				String message = "보내는 메시지-"+i; // 전송 메시지 생성
				os.write(message.getBytes("UTF-8")); // 전송 메시지 -> 바이트 열로 변환해서 송신
				// charset이 보내는 측과 받는 측이 같아야지 문자가 깨지지 않고 출력할 수 있다.
				
				// 명령 프롬프트에서 문자열을 바꾸는 방법은 chcp이며 UTF-8을 지정하기 위해서는 chcp 65001을 작성하면 된다.
				// 연결할 때는 telnet localgost 포트번호
				
				// Sent CRLF (***) : Enter Key도 보내자! why? 그렇지 않으면 메시지가 1줄로 쭉 나오기 때문이다.
				os.write(CR);
				os.write(LF);
				
				os.flush(); // 강제 flush
				
				log.info("SENT : {}",message);
				
				Thread.sleep(1000*1); // 1초 간격으로
				
			} //for	
			
		} catch (Exception e ) { // 예외처리
			e.printStackTrace();
		} finally {
			try {this.os.close();} catch (IOException e) { ;; } // 소켓 속에서 입력스트림을 얻었기에, 입력스트림을 먼저 닫고
			try {this.sock.close();} catch (IOException e) { ;; } // 소켓을 닫는다
		} // try - catch -finally
		
//		===============================================
		
	} // run()
	

} // end class

더보기

07. 멀티 스레드를 위한 데이터 송신 스레드 2

package tcp_practice;

import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;

import lombok.extern.log4j.Log4j2;


@Log4j2
public class Sender07 extends Thread {
	
//	===============================================
	
	private Socket sock; // ServerSocket
	private OutputStream os; // OutputStream
	
//	===============================================
	
	Sender07(String threadName, Socket sock ){
		
		log.debug("Constructor invoked.",sock);
		
		this.sock = sock;
		
		super.setName(threadName + "-" + super.getName());
		
		try {this.os = this.sock.getOutputStream();}
		catch(IOException e) { ;; }
		
	} // Sender01
	
//	===============================================
	
	@Override
	public void run() { // 데이터 송신 스레드의 실행진입점
		
		log.debug("run() invoked.");
		
		try {
			
			ObjectOutputStream oos = new ObjectOutputStream(this.os);
			
//			===============================================
			
			try	(oos){
				
				for (int i=0; i<10; i++) {
					
					String message = "서버가 보내는 메시지-"+i;
					
					oos.writeObject(message);
					oos.flush();
					
					log.info("SENT :{}", message);
					
					Thread.sleep(1000*1);
					
				} // for
				
			} // inner try
			
//			===============================================
			
		} catch (Exception e ) { // 예외처리
			e.printStackTrace();
		} finally {
			try {this.os.close();} catch (IOException e) { ;; } // 소켓 속에서 입력스트림을 얻었기에, 입력스트림을 먼저 닫고
			try {this.sock.close();} catch (IOException e) { ;; } // 소켓을 닫는다
		} // try - catch -finally
		
//		===============================================
		
		log.info("DONE.");
		
	} // run()
	

} // end class

더보기

08. 멀티 스레드의 역할 - 스레드가 1개 일때, 2가지의 일을 동시에 할 수 있을까?

package practice_thread;

import java.awt.Toolkit;



// 이 예제는 single thread 하나로 2가지 작업을 어떻게 수행하는지 보여주는 사례
// 스레드가 1개이기 때문에, 2가지 작업을 순차적으로 수행할 수 밖에 없음을 보여준다.
//
public class BeepPrintExample1 { // 1개의 스레드로 2가지 일
	
	public static void main(String [] args) {
		
		Toolkit toolkit = Toolkit.getDefaultToolkit();
		
		for(int i=0; i<5; i++) { // 1st case
			toolkit.beep(); // 띵 소리 출력
			
			try { Thread.sleep(500); } // 밀리초 단위로 스레드의 실행흐름을 지정된 시간동안 잠시 멈춤
			catch (Exception e) { ;; } 
			
		} // for1
		
		for(int i=0; i<5; i++) { // 2st case
			System.out.println("띵"); // 콘솔로 출력하는 "띵" 문자
			
			try { Thread.sleep(500); } // // 밀리초 단위로 스레드의 실행흐름을 지정된 시간동안 잠시 멈춤
			catch (Exception e) { ;; }
			
			// 코드 실행이 시간을 두며, 띵이라는 소리가 5번 난 다음에, 콘솔창에 "띵"이 5번 출력된다.
			
		} // for2
		
		
	} // main

} // end class

더보기

09. 멀티 스레드 구현

package practice_thread;

import java.awt.Toolkit;

public class BeepPrintExample2 { 
	
	// 이전 예제의 2가지 작업을 Worker Thread를 만들어서 동시에 수행시키자!
	
	public static void main(String [] args) { // Worker Thread를 만들어서 멀티 태스킹 1
		
		// 1. 작업 스레드 ( Worker Thread )를 만드는 첫 번째 방법
		Runnable beepTask = new BeepTask();
		Thread thread = new Thread(beepTask);
		// Thread( ) 안에는 Runnable한 객체만 넣을 수 있다.
		
//		=======================================================
		
		// 1번째 작업
		thread.start(); // Thread의 .start를 해야지만 진정으로 run해서 새로운 실행흐름이 생성된다.
		
//		=======================================================
		
		// 2번째 작업
		for(int i=0; i<5; i++) {
			
			System.out.println("띵"); // 콘솔로 출력하는 "띵" 문자
			
			try { Thread.sleep(500); } // // 밀리초 단위로 스레드의 실행흐름을 지정된 시간동안 잠시 멈춤
			catch (Exception e) { ;; }
			
		} // for
		
		// 소리와 출력이 동시에 이루어지고 있다.
		
//		=======================================================
		
		// 출력 :
		
//		띵
//		BeepTask::run() invoked.
//		띵
//		띵
//		띵
//		띵
		
		// 각자 스레드가 동시에 따로 실행되다 보니, BeepTask::run() invoked.의 위치는 달라질 수 있다. 
		
//		=======================================================
		
		// 2. Worker thread를 만드는 2번째 방법 ( 익명 구현 객체 )
		
		Thread thread2 = new Thread(new Runnable() {
		
			@Override
			public void run() {
			
				System.out.println("Anonymous::run() invoked.");
			
				Toolkit toolkit = Toolkit.getDefaultToolkit();
			
				for(int i=0; i<5; i++) { 
					toolkit.beep(); // 띵 소리 출력
				
					try { Thread.sleep(500); } // 밀리초 단위로 스레드의 실행흐름을 지정된 시간동안 잠시 멈춤
					catch (Exception e) { ;; } 
				
				} // for - sound 띵
			
			} // run
		
		}); // 익명구현객체 코딩 기법으로 만든 익명구현객체
		
		thread2.start();
		
//		=======================================================
		
		// 2번째 작업
		
		for(int i=0; i<5; i++) {
		
			System.out.println("띵"); // 콘솔로 출력하는 "띵" 문자
		
			try { Thread.sleep(500); } // // 밀리초 단위로 스레드의 실행흐름을 지정된 시간동안 잠시 멈춤
			catch (Exception e) { ;; }
		
		} // for
		
//		=======================================================
		
		// 출력 :	
//					띵
//					Anonymous::run() invoked.
//					띵
//					띵
//					띵
//					띵
		
//		=======================================================
		
		// 3. 람다식으로 working Thread 생성 (****)
		
		Thread thread3 = new Thread( () -> {
			
				System.out.println("Lambda::run() invoked.");
			
				Toolkit toolkit = Toolkit.getDefaultToolkit();
			
				for(int k=0; k<5; k++) { 
					toolkit.beep(); // 띵 소리 출력
				
					try { Thread.sleep(500); } // 밀리초 단위로 스레드의 실행흐름을 지정된 시간동안 잠시 멈춤
					catch (Exception e) { ;; } 
				
				} // for - sound 띵
			
		}); // 람다식을 이용한 익명 구현 객체 생성
		
		thread3.start();
		
//	=======================================================
	
	// 2번째 작업
	
		for(int j=0; j<5; j++) {
	
			System.out.println("띵"); // 콘솔로 출력하는 "띵" 문자
	
			try { Thread.sleep(500); } // // 밀리초 단위로 스레드의 실행흐름을 지정된 시간동안 잠시 멈춤
			catch (Exception e) { ;; }
	
		} // for
		
	} // main

} // end class
package practice_thread;

import java.awt.Toolkit;

import lombok.NoArgsConstructor;


// 함수적 인터페이스인 Runnable을 구현하는 구현 클래스 선언 (***)

@NoArgsConstructor
public class BeepTask implements Runnable { // 멀티 스레드 만드는 방법 1  

	@Override
	public void run() {
		
		System.out.println("BeepTask::run() invoked.");
		
		Toolkit toolkit = Toolkit.getDefaultToolkit();
		
		for(int i=0; i<5; i++) { 
			toolkit.beep(); // 띵 소리 출력
			
			try { Thread.sleep(500); } // 밀리초 단위로 스레드의 실행흐름을 지정된 시간동안 잠시 멈춤
			catch (Exception e) { ;; } 
			
		} // for - sound 띵
		
	} // run

} // end class

더보기

10. 멀티 스레드 구현 2

package practice_thread;

import java.awt.Toolkit;

public class BeepPrintExample3 { 
	
	public static void main(String [] args) { // Worker Thread를 만들어서 멀티 태스킹 2
		
		// how 1 - 자식 스레드 클래스를 이용하여, 스레드 객체 사용
		
		Thread thread1 = new BeepThread();
		thread1.start();
		
//		====================================================================
		
		for(int i=0; i<5; i++) {
		
			System.out.println("띵"); // 콘솔로 출력하는 "띵" 문자
		
			try { Thread.sleep(500); } // // 밀리초 단위로 스레드의 실행흐름을 지정된 시간동안 잠시 멈춤
			catch (Exception e) { ;; }
		
		} // for1
		
//		====================================================================
		
		// how 2 - 익명자식객체코딩 기법으로 Thread 클래스의 "자식" 객체를 빠르게 만드는 방법 사용 (***)
		
		Thread thread2 = new Thread() {
			
			@Override
			public void run() {
				
				Toolkit toolkit = Toolkit.getDefaultToolkit();
				
				System.out.println("thread2::run() invoked.");
				
				for ( int i = 0; i < 5; i++) {
					toolkit.beep();
					
					try { Thread.sleep(500); } catch (Exception e) { ;; }
					
				} // for
				
			} // run
		
		}; // thread2
		
		// 스레드의 이름 ( default naming : Thread - n ) :
		thread2.setName("Yoseph-Thread"); // setName으로 메소드의 이름을 지정할 수 있다. ( start 전에 만들어야 한다. )
		thread2.start();
		
//		====================================================================
		
		for(int i=0; i<5; i++) {
		
			System.out.println("띵"); // 콘솔로 출력하는 "띵" 문자
		
			try { Thread.sleep(500); } // // 밀리초 단위로 스레드의 실행흐름을 지정된 시간동안 잠시 멈춤
			catch (Exception e) { ;; }
		
		} // for2
		
//		====================================================================
		
		// 출력 :
		
//		띵
//		BeepThread::run() invoked.
//		띵
//		띵
//		띵
//		띵
//		띵
//		thread2::run() invoked.
//		띵
//		띵
//		띵
//		띵
		
//		====================================================================
		
		// 이때 thread2는 for1이 끝나고 나서 생성되고 시작되기에 나중에 발생한다. 
		
	} // main

} // end class
package practice_thread;

import java.awt.Toolkit;


// Thread 클래스를 상속받는 자식 클래스를 만들고, 물려받은 메소드인 run() 메소드를 재정의하여
// 새로운 스레드 객체를 생성한다.
public class BeepThread extends Thread { // 스레드 생성 방법 - 자식 클래스 
	
	@Override
	public void run() {
		
		System.out.println("BeepThread::run() invoked.");
		
		Toolkit toolkit = Toolkit.getDefaultToolkit();
		
		for(int i=0; i<5; i++) { 
			toolkit.beep(); // 띵 소리 출력
			
			try { Thread.sleep(500); } // 밀리초 단위로 스레드의 실행흐름을 지정된 시간동안 잠시 멈춤
			catch (Exception e) { ;; } 
			
		} // for - sound 띵
		
	} // run

} // end class
728x90
댓글
«   2024/09   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
최근에 올라온 글
Total
Today
Yesterday
공지사항