Flaming Soccer ball
JAVA

28일차 22.10.31

leo lee 2022. 10. 31.
반응형

Multi Thread: 2개 이상의 스레드가 수행중인 상황
대부분의 경우
1) Priority(우선 순위): 누가 먼저, 자주
I/O(파일 입출력, 네트워크 입출력, 화면 출력): 시간이 오래 걸리는 작업
연산: 시간이 짧게 걸리는 작업 

2) Thread Group: 여러 개의 스레드 관리
Semaphore

3) Mutual Exclusion(상호 배제)
-> 하나의 스레드가 사용 중인 공유 자원은 다른 스레드가 수정 할 수 없음
-> Lock과 Synchronized(순서대로)로 해결 <-> Asynchronized(순서를 알 수 없음)

4) 생산자와 소비자 문제
-> wait와 notification으로 해결 

5) DeadLock
-> 결코 발생할 수 없는 사건을 무한정 기다리는 것 

8. Thread Group
-> 관련된 스레드들을 하나의 그룹으로 묶어서 사용하기 위한 개념
-> ThreadGroup 이라는 클래스를 제공하지만 몇 몇 메서드가 제대로 동작하지 않는 문제 때문에 대부분의 경우 배열이나 List를 이용해서 구현하는 것을 권장

9. Thread의 종료 
-> run 메서드 종료
-> 스레드의 Interrupt 메서드를 호출하고 스레드의 run 메서드 안에서 InterruptedException이 발생하면 run 메서드를 종료하도록 만들어서 강제 종료하도록 할 수 있음
-> Daemon Thread는 Daemon이 아닌 다른 스레드가 존재하지 않으면 자동으로 종료  
-> Thread의 실행 제어 메서드
void join(long millis, int nanos): 지정된 시간 동안 스레드를 수행하고 다른 스레드에게 제어권을 넘기는 메서드

void suspend( ): 스레드를 일시 정지 시키는 메서드로 resume 메서드로 다시 시작

void resume( ): suspend된 스레드를 다시 시작

void yield( ): 다른 스레드에게 제어권을 넘겨 주는 메서드

10. Mutual Exclusion(상호 배제)
-> 하나의 스레드가 사용 중인 공유 자원을 다른 스레드가 수정하면 안됨
1) 공유 자원을 여러 개의 스레드가 동시에 사용했을 때 문제
-> 공유 자원으로 사용할 데이터 클래스 

=> 실습

 

package naver.srlee3637.multithread;

//자원을 가지고 연산을 하는 스레드에 사용할 클래스
public class ShareData implements Runnable {

	//연산 결과를 저장할 속성
	private int result;
	//연산에 사용할 인덱스
	private int idx;

	//result의 getter메서드
	public int getResult(){
		return result;
	}

	@Override
	public void run() {
		try {
			for(int i = 0; i < 5; i++) {
				idx++;
				Thread.sleep(10);
				result = result + idx;
			}

		} catch (Exception e) {
			System.out.println(e.getLocalizedMessage());
		}
	}
}

 

package naver.srlee3637.multithread;

public class MutexMain {

	public static void main(String[] args) {
		//Runnable 인터페이스로 부터 상속 받은 클래스
		ShareData shareData = new ShareData();
		//스레드 생성
		Thread th1 = new Thread(shareData);
		th1.start();
		Thread th2 = new Thread(shareData);
		th2.start();
		
		try {
			//30초 대기 - 앞의 작업이 스레드로 동작하기 때문에 작업이 끝날 때 까지 대기하고 결과 출력 
			Thread.sleep(3000);
			System.out.println(shareData.getResult());
		} catch (Exception e) {
			System.out.println(e.getLocalizedMessage());
		}
	}

}



--> 실행을 하면 이상한 결과가 출력됨
ShareDate 인스턴스를 1개만 만들어서 공유하는데 하나의 작업이 완료되기 전에 다른 스레드가 공유 자원을 수정하기 때문에 발생

2) 해결 방법
-> 한번에 실행되어야 하는 코드를 가진 영역을 찾고 메서드에 synchronized를 붙이 던가 코드 영역을 synchronized(공유객체){ } 로 묶어 주면 됨
이렇게 묶어 주면 묶인 영역의 코드는 동시에 수정할 수 없음
되도록이면 synchronize 메서드를 만드는 것 보다는 블럭을 만드는 것을 권장
메서드를 묶게되면 영역이 커져서 공유도가 떨어지기 때문

3)ShareData 수정해서 다시

=> 실습

package naver.srlee3637.multithread;

//자원을 가지고 연산을 하는 스레드에 사용할 클래스
public class ShareData implements Runnable {
	
	//연산 결과를 저장할 속성
	private int result;
	//연산에 사용할 인덱스
	private int idx;
	
	//result의 getter메서드
	public int getResult(){
		return result;
	}
	
	@Override
	public void run() {
		
		try {
			for(int i = 0; i < 5; i++) {
				synchronized(this){
				idx++;
				Thread.sleep(10);
				result = result + idx;
				}
			}
			
		} catch (Exception e) {
			System.out.println(e.getLocalizedMessage());
		}
	}

	

}




4) 최근에는 위의 방법 말고 ReentrantLock이라는 클래스를 이용하는 것을 권장 
-> 인스턴스를 생성하고 lock이라는 메서드로 공유 영역을 만들고 unlock이라는 메서드로 공유 영역을 해제

=> 실습

package naver.srlee3637.multithread;

import java.util.concurrent.locks.ReentrantLock;

//자원을 가지고 연산을 하는 스레드에 사용할 클래스
public class ShareData implements Runnable {
	
	//연산 결과를 저장할 속성
	private int result;
	//연산에 사용할 인덱스
	private int idx;
	
	//공유 코드 영역을 설정하기 위한 객체
	static final ReentrantLock lock = new ReentrantLock();
	
	//result의 getter메서드
	public int getResult(){
		return result;
	}
	
	@Override
	public void run() {
		
		try {
			for(int i = 0; i < 10; i++) {
				//자물쇠를 채워서 unlock을 만날 때까지는 이 영역의 자원을 수정할 수 없음 
				lock.lock();
				idx++;
				Thread.sleep(10);
				result = result + idx;
				lock.unlock();

			}
			
		} catch (Exception e) {
			System.out.println(e.getLocalizedMessage());
		}
	}

	

}




11. 생산자와 소비자 문제
-> 생산자와 소비자는 동시에 수행할 수 있는데 소비자는 생산자가 자원을 생성해준 경우에만 동작을 해야함
소비자가 자원이 생성되지 않았는데 작업을 수행하면 예외 발생


1)생산자와 소비자 문제 발생
-> 공유 자원의 역할을 수행할 클래스 - Product
=> 실습 

package naver.srlee3637.multithread;

import java.util.ArrayList;
import java.util.List;

//공유 자원의 역할을 수행할 클래스 - 진열대 역할
public class Product {
	//문자를 저장할 수 있는 List -  공유 자원
	List<Character> list;
	
	//생성자
	public Product() {
		list = new ArrayList<>();
	}
	
	//생산자 메서드
	public void put(Character ch) {
		list.add(ch);
		System.out.println("창고에 제품 " + ch + "가 입고 되었습니다.");
		
		try {
			Thread.sleep(1000);
			System.out.println("재고 수량:" + list.size());
		} catch (Exception e) {
			System.out.println(e.getLocalizedMessage());
		}
	}
	
	//소비자 메서드
	public void get() {
		//첫번째 데이터를 꺼내서 ch에 대입
		Character ch = list.remove(0);
		System.out.println("창고에서 제품 " + ch + "를 출고 하였습니다.");
		
		try {
			Thread.sleep(1000);
			System.out.println("재고 수량:" + list.size());
		} catch (Exception e) {
			System.out.println(e.getLocalizedMessage());
		}
	}
	
}







-> 생산자 스레드 클래스: Producer
=> 실습

package naver.srlee3637.multithread;

public class Producer extends Thread {
	//공유자원 속성
	private Product myList;
	
	//생성자
	public Producer(Product myList) {
		this.myList = myList;
	}
	
	@Override
	public void run() {
		//삽입 작업을 26번 수행
		for(char ch = 'A'; ch <= 'Z'; ch++) {
			myList.put(ch);
		}
	}

}



-> 소비자 스레드 클래스: Customer
=> 실습

package naver.srlee3637.multithread;

public class Customer extends Thread {
	private Product myList;

	//생성자
	public Customer(Product myList) {
		this.myList = myList;
	}
	
	@Override
	public void run() {
		for(int i = 0; i < 26; i++) {
			myList.get();
		}
	}
}



-> main메서드를 소유한 클래스를 만들어서 스레드 2개를 실행 : ProducerConsumerMain
=> 실습

package naver.srlee3637.multithread;

public class ProducerConsumerMain {

	public static void main(String[] args) {
		//자원생성
		Product product = new Product();
		//하나의 자원을 이용해서 2개의 스레드를 생성해서 실행
		new Producer(product).start();
		new Customer(product).start();
	}

}



-> 실행을 하다보면 예외 발생 
소비자 스레드인 Customer 스레드가 리스트에 아무런 데이터가 없는데 꺼낼려고 해서 발생하는 문제
소비자 스레드의 메서드는 데이터가 없을 대는 대기하고 생산자 스레드는 데이터를 만들어 낸 경우 데이터가 만들어 졌다고 알려줘야함
기다리기 위해서 호출하는 메서드는 wait이고 알려주는 메서드는 notify 와 notifyAll이라는 메서드
이 메서드들은 Object클래스의 메서드 이고, Synchronze 메서드 안에서만 동작 

-> product클래스를 수정하고 실행 
=> 실습

package naver.srlee3637.multithread;

import java.util.ArrayList;
import java.util.List;

//공유 자원의 역할을 수행할 클래스 - 진열대 역할
public class Product {
	//문자를 저장할 수 있는 List -  공유 자원
	List<Character> list;
	
	//생성자
	public Product() {
		list = new ArrayList<>();
	}
	
	//생산자 메서드
	public synchronized void put(Character ch) {
		list.add(ch);
		System.out.println("창고에 제품 " + ch + "가 입고 되었습니다.");
		
		try {
			Thread.sleep(1000);
			System.out.println("재고 수량:" + list.size());
		} catch (Exception e) {}
		//물건을 생산했다고 알려줌
		notify();
	}
	
	//소비자 메서드
	public synchronized void get() {
		
		try {
			if(list.size() == 0) {
				wait();
			}
		} catch (Exception e) {}
		//첫번째 데이터를 꺼내서 ch에 대입
		Character ch = list.remove(0);
		System.out.println("창고에서 제품 " + ch + "를 출고 하였습니다.");
		
		try {
			Thread.sleep(1000);
			System.out.println("재고 수량:" + list.size());
			
		} catch (Exception e) {}
		//물건을 생산했고 알려줌	
	}
}


-> 다시 실행해 보면 예외가 발생하지 않음 

12. Dead Lock
-> 결코 발생할 수 없는 사건을 무한정 기다리는 것 
-> Synchronize 블럭이 여러 개 있는 경우 멀티 스레드를 사용하면 발생 

13. Semaphore
-> 동시에 사용할 수 있는 Thread의 개수를 제한
-> Semaphore 클래스를 이용해서 설정
-> 메서드
acquire( ): 리소스를 확보하는 메서드
release( ): 리소스를 해제하는 메서드

1)세마포어를 이용하지 않는 경우 - 스레드가 동시에 전부 실행
-> 스레드 클래스 : SemaphoreThread

=> 실습

package naver.srlee3637.multithread;

public class SemaphoreThread implements Runnable{
	
	String message;
	
	public SemaphoreThread(String message) {
		this.message = message;
	}
	
	@Override
	public void run() {
		try {
			Thread.sleep(10000);
			System.out.println(message);
		} catch (Exception e) {}
	}

}




-> main 메서드를 소유한 클래스를 만들어서 실행: SemaphoreMain
=> 실습

package naver.srlee3637.multithread;

public class SemaphoreMain {

	public static void main(String[] args) {
		Thread th1 = new Thread(new SemaphoreThread("카리나"));
		Thread th2 = new Thread(new SemaphoreThread("지젤"));
		Thread th3 = new Thread(new SemaphoreThread("윈터"));
		Thread th4 = new Thread(new SemaphoreThread("닝닝"));
		
		th1.start();
		th2.start();
		th3.start();
		th4.start();
	}

}




-> 4개의 Thread가 10초 동시에 메세지를 출력 


2) 세마포어를 이용하도록 수정 

-> 스레드 클래스 수정 
=> 실습

package naver.srlee3637.multithread;

import java.util.concurrent.Semaphore;

public class SemaphoreThread implements Runnable{
	
	String message;
	Semaphore semaphore;
	
	public SemaphoreThread(String message, Semaphore semaphore) {
		this.message = message;
		this.semaphore = semaphore;
	}
	
	@Override
	public void run() {
		try {
			//리소스 확보
			semaphore.acquire();
			Thread.sleep(10000);
			System.out.println(message);
		} catch (Exception e) {}
		//리소스 해제
		semaphore.release();
	}

}



-> 메인 클래스 수정

=> 실습

package naver.srlee3637.multithread;

import java.util.concurrent.Semaphore;

public class SemaphoreMain {

	public static void main(String[] args) {
		//2개씩 실행할 수 있는 세마포어
		Semaphore semaphore = new Semaphore(2);
		Thread th1 = new Thread(new SemaphoreThread("카리나", semaphore));
		Thread th2 = new Thread(new SemaphoreThread("지젤", semaphore));
		Thread th3 = new Thread(new SemaphoreThread("윈터", semaphore));
		Thread th4 = new Thread(new SemaphoreThread("닝닝", semaphore));
		
		th1.start();
		th2.start();
		th3.start();
		th4.start();
	}

}


**정규 표현식
1. 개요
-> 문자열의 집합을 표현하는데 사용하는 형식 언어
-> Perl에서 처음 사용
-> 많은 프로그래밍 언어가 정규 표현식 기능을 제공 하고 있는데 언어 자체가 제공하기도 하고 별도의 라이브러리 형태로 제공되기도 함
-> 문자열 패턴을 검사하기 위해서 사용
유효성 검사나 자연어 처리에서 많이 사용
-> java에서는 java.util.regex 패키지에 있는 Match 클래스와 Pattern 클래스 그리고 String 클래스에서 제공 
-> Web Programming에서는 Java보다는 Javascript에서 많이 사용

2. Network - java.net
-> 다른 컴퓨터와 통신을 하기 위해서는 다른 컴퓨터의 프로그램이나 자원에 접근하기 위한 주소를 알아야함
프로그램에 접근할 때는 IP(컴퓨터를 구분하기 위한 주소)와 포트(프로세스를 구분하기 위한)번호 또는 Domian을 알아야함

1)통신 절차
-> 요청을 처리하는 쪽에서 포트번호를 가지고 소켓을 생성해서 시작
-> 요청을 보내는쪽에서 요청을 처리하는 쪽의 구별하기 위한 주소를 가지고 접속을 하고 요청을 전송
-> 요청을 처리하는 쪽에서 요청을 보내는 쪽의 데이터(parameter)를 읽어서(여기까지가 Request) 
처리를 수행한 후 처리 결과를 요청을 보내는쪽으로 전송
-> 요청을 보내는 것을 Request라고 하고 요청을 처리해서 결과를 전송하는 것을 Response라고 함 

2) TCP 형태로 클라이언트와 서버가 대화를 주고 받는 것(클라이언트가 서버에게 전송하면 서버가 다시 응답하는 것 

TCPServer 작성
=> 실습

 

package naver.srlee3637.network;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class TCPServer {

	public static void main(String[] args) {
		//try ~ resources 구문으로 메모리 해제를 하지 않아도 됨
		try(ServerSocket ss = new ServerSocket(9999);) {
			System.out.println("서버 대기 중...");
			
			//클라이언트의 요청 대기
			try {
				Socket socket = null;
				while(true) {
					//클라이언트의 요청을 대기하다가 클라이언트의 요청이 오면 접속
					socket = ss.accept();
					//접속자 정보 출력
					System.out.println("접속자 정보: " + socket.toString());
					//접속자와 문자열을 읽을 수 있는 스트림 생성
					BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
					//한줄의 메세지 읽기
					String message = br.readLine();
					System.out.println(message);
					
					//메세지를 보낼 수 잇는 스트림을 생성
					PrintWriter pw = new PrintWriter(socket.getOutputStream());
					pw.println("서버가 보내는 메세지");
					pw.flush();
					
					
					//정리 작업
					pw.close();
					br.close();
					socket.close();
				}
			} catch (Exception e) {
				System.out.println(e.getLocalizedMessage());
			} finally {
				
			}
		} catch (Exception e) {
			System.out.println(e.getLocalizedMessage());
		}
	}

}




TCPClient 작성: 자기 컴퓨터에 전송할 때는 127.0.0.1이나 localhost라고 하면 됨
외부의 컴퓨터에서 내 컴퓨터로 데이터가 전송이 가능하도록 할 때는 방화벽을 해제해 주어야 함
=> 실습

package naver.srlee3637.network;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Scanner;

public class TCPClient {

	public static void main(String[] args) {
		try( Scanner sc = new Scanner(System.in);) {
			
			
			while(true) {
				Socket socket = new Socket(InetAddress.getByName("172.30.1.97"),9999);
				System.out.print("보낼 메세지:");
				String message = sc.nextLine();
				
				//메시지 보내기
				PrintWriter pw = new PrintWriter(socket.getOutputStream(), true);
				pw.println(message + "\n");
				pw.flush();
				
				
				//메시지 받기 
				BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
				String response = br.readLine();
				System.out.println(response);
				br.close();
				pw.close();
			}
			
		} catch (Exception e) {
			System.out.println(e.getLocalizedMessage());
		}

	}

}



반응형

'JAVA' 카테고리의 다른 글

30일차 22.11.02 JSON파일 읽어오기  (0) 2022.11.02
27일차 22.10.28  (0) 2022.10.28
26일차 22.10.27  (0) 2022.10.27
25일차 22.10.26  (0) 2022.10.26
24일차 22.10.25  (0) 2022.10.25

댓글