Java

05.19 스레드,네트워크

amungstudy 2023. 5. 23. 09:11

 

동기화 메소드 및 동기화 블록 – synchronized

단 하나의 스레드만 실행할 수 있는 메소드 또는 블록

다른 스레드는 메소드나 블록이 실행이 끝날 때까지 대기해야

 

package t04_sync;

 

public class ThreadSyncEX {

 

public static void main(String[] args) {

Runnable work = new WithDrawThread();

Thread thread1 = new Thread(work);

Thread thread2 = new Thread(work);

 

thread1.setName("스레드 1");

thread2.setName("스레드 2");

thread1.start();

thread2.start();

 

 

}

 

}

 

class Account{

// 현재 등록된 금액

private int balance = 10000;

 

public int getBalance() {

return this.balance;

}

 

// 출금

//synchronized

// public synchronized boolean withdraw(int money) {

public synchronized boolean withdraw(int money) {

// 출금 가능한 금액

if(balance >= money) {

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

balance -= money;

return true;

}

// 출금 할 수 없는 금액

return false;

}

}

 

// 출금 작업 스레드 기능 구현 객체

class WithDrawThread implements Runnable{

 

Account account = new Account();

 

@Override

public void run() {

while(account.getBalance() > 0) {

// 1000 ~ 5000 : 출금 금액 랜덤 생성

int money = (int)(Math.random() * 5 + 1 ) * 1000;

 

// Account 클래스를 직접적으로 수정하지 못하는 경우

boolean isDenied = false;

// 임계영역 지정

synchronized (account) { //lock

isDenied = account.withdraw(money);

}

 

 

if(!isDenied) {

System.out.println("출금 금액 부족 거부");

}else {

System.out.printf(

"%s 출금 : %d원 남은 금액 : %d원 %n",

Thread.currentThread().getName(),

money,

account.getBalance()

);

}

}

}

}

 

 

 

스레드간 협업 – wait(), notify(), notifyAll()

 

동기화 메소드 또는 블록에서만 호출 가능한 Object의 메소드

두 개의 스레드가 교대로 번갈아 가며 실행해야 할 경우 주로 사용

 

package t05_control_method.notify_wait;

 

public class DataBox {

 

private String data;

 

// notify, wait 은 임계영역 안에서만 사용 가능함.

synchronized String getData() {

if(this.data == null ) {

try {

wait();

} catch (InterruptedException e) {}

}

String value = this.data;

this.data = null;

System.out.println("읽은 데이터 : " + value);

notify();

return value;

}

 

synchronized void setData(String data) {

if(this.data != null) {

try {

wait();

} catch (InterruptedException e) {}

}

this.data = data;

System.out.println("생성한 데이터 : " + data);

notify();

}

 

}

 

 

 

package t06_stop_thread;

// 스레드 안전하게 종료시키는 방법 1 - flag이용

class PrintThread extends Thread{

 

private boolean isRun = true;

 

public void setIsRun(boolean isRun) {

this.isRun = isRun;

}

 

@Override

public void run() {

while(isRun) {

System.out.println("실행중....");

}

System.out.println("자원정리");

System.out.println("실행종료");

}

 

}

 

 

public class StopFlagExample {

 

public static void main(String[] args) {

PrintThread t = new PrintThread();

t.start();

 

try {

Thread.sleep(1000);

} catch (InterruptedException e) {}

// 플래그를 이용하면 run메소드 안전하게 실행하고 정지

t.setIsRun(false);

 

 

}

 

}

 

 

 

package t06_stop_thread;

// 스레드 안전하게 종료시키는 방법 2

class InterruptThread extends Thread{

 

public void run() {

// 외부에서 이 스레드를 중단시키라고 interrupt 호출하면 true로 변경됨.

boolean isInterrupted = Thread.interrupted();

System.out.println(isInterrupted);

while(true) {

System.out.println("실행 중 -1");

isInterrupted = Thread.interrupted();

if(isInterrupted) {

break;

}

}

System.out.println("자원해제");

System.out.println("실행종료");

}

 

}

 

 

public class InterruptedExample {

 

public static void main(String[] args) {

InterruptThread it = new InterruptThread();

it.start();

 

try {

Thread.sleep(1000);

} catch (InterruptedException e) {}

it.interrupt();

}

 

}

 

 


package n1_socket;

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

public class ClientExample {

public static void main(String[] args) {
//소켓 생성 시 ip주소, port번호 입력 & server에 연결됨 
try {
System.out.println("[ server에 연결 요청]");
// socket : 서버에 대한 정보 전달 받음
Socket socket = new Socket("10.100.205.177",5001);
System.out.println("[server 연결 성공]");

InputStream is = socket.getInputStream();
byte[] bytes = null;
String message = null;

bytes = new byte[100];
int readByteCount = is.read(bytes); // stream에서 값이 전달될때까지 blocking
message = new String(bytes,0,readByteCount,"UTF-8");
System.out.println("[데이터 받기 성공]" + message);

OutputStream os = socket.getOutputStream();
message = "2분남았다";
bytes = message.getBytes("UTF-8");
os.write(bytes);
os.flush();
System.out.println("[데이터 발신 완료]");

} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}

}

}


package n1_socket;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;

public class ServerExample {

public static void main(String[] args) {

try {
ServerSocket server = new ServerSocket(5001);
while(true) {
System.out.println("Client 연결 대기중");

//client에 연결요청 보낸 client 정보가 들어감.
Socket client = server.accept(); // client의 연결요청이 올때까지 blocking.

System.out.println("client 연결 수락");
//getRemoteSocketAddress: client 정보를 추상클래스로 반환해줌
InetSocketAddress isa 
= (InetSocketAddress)client.getRemoteSocketAddress();
//getHostName() : client 이름 정보
System.out.println(" - "+isa.getHostName());

byte[] bytes = null;
String message = null;

OutputStream os = client.getOutputStream();
message = "또 올거냐??";
bytes = message.getBytes("UTF-8");
os.write(bytes);
os.flush();
System.out.println("client에 데이터 발송");

InputStream is = client.getInputStream();
bytes = new byte[100];

int readCount = is.read(bytes);
message = new String(bytes,0,readCount,"UTF-8");
System.out.println("client에서 전달 받은 데이터 : "+ message);




}
} catch (IOException e) {
e.printStackTrace();
}

}

}