JAVA

JAVA 7주차

Zㅣ존수빈zz 2022. 12. 15. 17:20

1. Synchronized (동기화)

- 하나의 클래스를 두 쓰레드가 사용할 때 synchronized를 사용하여 하나의 변수를 공유하도록 한다.

// 동기화 하지 않았을 경우 - 서로 다른 쓰레드가 변수를 각자 따로 사용
public class Sync1 {
	public static void main(String[] args) {
		MyTicket myTicket = new MyTicket();		
		Thread t1 = new Thread(myTicket);
		Thread t2 = new Thread(myTicket);
		t1.start();
		t2.start();
	}
}

class MyTicket implements Runnable {
	private int ticket = 10;

	@Override
	public void run() {
		for(int i=0; i<10; i++) {
			try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}
			sellTicket();
		}
	}
	
	public void sellTicket() {
		ticket -= 1;
		if(ticket <= 0) {
			System.out.println("좌석이 남아있지 않습니다.");
			return;
		}
		System.out.println("현재 좌석은 "+ticket+"개 남았습니다.");
	}
	
}

// 결과:
//현재 좌석은 8개 남았습니다.
//현재 좌석은 8개 남았습니다.
//현재 좌석은 7개 남았습니다.
//현재 좌석은 7개 남았습니다.
//현재 좌석은 6개 남았습니다.
//현재 좌석은 6개 남았습니다.
//현재 좌석은 4개 남았습니다.
//현재 좌석은 4개 남았습니다.
//현재 좌석은 3개 남았습니다.
//현재 좌석은 3개 남았습니다.
//현재 좌석은 2개 남았습니다.
//현재 좌석은 2개 남았습니다.
//좌석이 남아있지 않습니다.
//현재 좌석은 0개 남았습니다.
//좌석이 남아있지 않습니다.
//좌석이 남아있지 않습니다.
// 동기화했을 경우 - 서로 다른 쓰레드 객체가 하나의 변수를 공유
package Day12;

public class Sync1 {
	public static void main(String[] args) {
		MyTicket myTicket = new MyTicket();
		
		Thread t1 = new Thread(myTicket);
		Thread t2 = new Thread(myTicket);
		t1.start();
		t2.start();
	}
}

class MyTicket implements Runnable {
	private int ticket = 10;
	@Override
	public void run() {
		for(int i=0; i<10; i++) {
			try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}
			sellTicket();
		}
	}
	
	public synchronized void sellTicket() {		// 동기화된 함수: 변수를 사용할 때 중첩되지 않는다.
		ticket -= 1;
		// 티켓 판매 후 남은 좌석 체크
		if(ticket <= 0) {
			System.out.println("좌석이 남아있지 않습니다.");
			return;
		}
		System.out.println("현재 좌석은 "+ticket+"개 남았습니다.");
	}
}

// 결과
//현재 좌석은 8개 남았습니다.
//현재 좌석은 7개 남았습니다.
//현재 좌석은 6개 남았습니다.
//현재 좌석은 5개 남았습니다.
//현재 좌석은 4개 남았습니다.
//현재 좌석은 3개 남았습니다.
//현재 좌석은 2개 남았습니다.
//현재 좌석은 1개 남았습니다.
//좌석이 남아있지 않습니다.
//좌석이 남아있지 않습니다.

2. Stream

- 파일 검색, 읽기, 만들기, 삭제하기

  • C드라이브의 모든 파일 혹은 폴더를 배열로 저장하여 출력하기
public class Stream1 {
	public static void main(String[] args) {
		FileFound ff = new FileFound();
		ff.go("c:\\");
	}
}

class FileFound {
	public void go(String path) {
		System.out.println(path+"안에 있는 파일 검색");
		File file = new File(path);			// File 클래스에 경로를 넘겨줌
		String file_list[] = file.list();	// 모든 파일 목록 배열로 저장
		
		// 가져온 파일 목록을 반복문을 통해 하나씩 보여주기
		for(int i=0; i<file_list.length; i++) {
			System.out.println((i+1)+". "+file_list[i]);
		}
		
		// 빠른 for문 - python형태의 for문으로 배열길이가 정해져있고 의도가 명확할 때 사용할 수 있다.
		for(String str : file_list) {
			if(str.contains(".")){
				System.out.println("폴더명: "+ str);
			}else {
				System.out.println("파일명: "+str);
			}
		}
		
	}
}

 

  • 지정한 위치에 파일 만들고 삭제하기
import java.io.File;
import java.io.IOException;
import java.util.Scanner;

public class Stream2 {
	public static void main(String[] args) {
		FileCtrl fc = new FileCtrl();
		int result = fc.delFile("C:\\java");
					// fc.makeFile("C:\\java");
		System.out.println(result);
	}
}

class FileCtrl {
	// 파일 만들기
	public int makeFile(String path) {			// 생성에 실패하면 0, 성공하면 1을 반환
		int isSuccess = 0;
		Scanner sc = new Scanner(System.in);
		System.out.println("생성할 파일 이름을 입력하세요(확장자까지)>>");
		String filename = sc.nextLine();
		File file = new File(path + "\\" + filename);
		
		if(file.exists()) {
			System.out.println("이미 존재하는 파일입니다.");
			return -1;
		}
		
		try {
			file.createNewFile();
			isSuccess = 1;
		} catch (IOException e) {
			isSuccess = 0;
			e.printStackTrace();
		} finally {
			sc.close();
		}
		if(file.exists()) {
			System.out.println("파일 생성 완료!");
		}
		return isSuccess;
	}
	
	// 파일 삭제하기
	public int delFile(String path) {
		Scanner sc = new Scanner(System.in);
		System.out.println("삭제할 파일 이름을 입력하세요(확장자까지)>>");
		String filename = sc.nextLine();
		File file = new File(path + "\\" + filename);
		boolean isDeleted = file.delete();
		if(isDeleted) {
			System.out.println("삭제 성공!");
			return 1;
		}else {
			System.out.println("삭제 실패...");
			return 0;
		}
	}
}
  • 파일에 내용입력하고 읽어오기
    파일은 '바이트'단위로 적기 때문에 문자열을 바이트로 바꿔주는 절차를 거쳐야 한다 
    - FileOutputStream: byte 단위로 파일을 내보내는 메서드
    - InputStream: byte단위의 파일을 다시 문자열로 받아오는 메서드
    - InputStreamReader:  문자열 형식을 UTF-8로 변환하기 위하여 사용
    - BufferedFeader: 문자열로 바꾸기 위해 버퍼단위로 읽음
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Scanner;

public class Stream3 {
	public static void main(String[] args) {
		MyFileIO fio = new MyFileIO();
		fio.putText("C:\\java\\test.txt");
		fio.readText("C:\\java\\test.txt");
	}
}

class MyFileIO {
	// 파일에 내용 입력하기(OutputStream)
	public void putText(String file) {
		FileOutputStream fout = null;		// byte단위로 내보내는 메서드
		Scanner sc = null;
		
		try {
			fout = new FileOutputStream(file, true);	// true가 없으면 기존의 내용 삭제 후 입력(덮어씀) 
			sc = new Scanner(System.in);
			System.out.print("입력할 내용>>");
			String msg = sc.nextLine()+" \n";
			
			// 문자열을 바이트로 바꾸기
			byte[] byteArray = msg.getBytes();
			fout.write(byteArray);
			
			System.out.println("입력완료");
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println("입력실패...");
		} finally {
			try {
				fout.close();
				sc.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
		
	// 파일 읽어오기(InputStream)
	public void readText(String file) {
		FileInputStream fin = null;
		
		try {
			fin = new FileInputStream(file);	// 파일을 불러온다
			
			// UTF-8로 변환한다
			InputStreamReader isr = new InputStreamReader(fin, "UTF-8");
			BufferedReader br = new BufferedReader(isr);
			
			String msg = null;
			while((msg = br.readLine()) != null) {
				System.out.println(msg);
			}
		} catch(Exception e) {
			e.printStackTrace();
			System.out.println("파일 읽기 실패...");
		} finally {
			try {
				fin.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}

3. socket

- 프로그램 간 메시지 주고받기

- 소켓통신을 하려면 같은 네트워크를 사용해야 한다.

- ObjectInputStream: 파일이나 네트워크를 통해 전달 받은 직열화된 데이터를 다시 직렬화 하기전 객체로 만드는 것

  readObject()와 함께 쓰인다.

- ObjectOutputStream : 파일이나 네트워크로 데이터를 전달하기 위해 직렬화를 수행. writeObject() 함수를 이용해서 변환

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

public class Socket1 {
	public static void main(String[] args) {
		MyServer ms = new MyServer();
		MyClient mc = new MyClient();

		// mc.go("접속할 서버IP주소", 접속할 포트번호)
		// ms.go(서버관리자가 정하는 포트번호);
	}
}

// TCP / IP 통신을 Socket으로 진행
class MyServer {
	// 들어오는 메시지(수신)
	InputStream is;
	ObjectInputStream ois;
	// 나가는 메시지(송신)
	OutputStream os;
	ObjectOutputStream oos;
	// 서버로 설정
	ServerSocket serverSocket;
	// 메시지를 직접적으로 처리할 소켓을 추가생성
	Socket socket;
	String msg;
	
	public void go(int port) {			// 서버는 컴퓨터의 IP(주소)와 설정한 PORT(대상)로 연결을 시작

		try {
			serverSocket = new ServerSocket(port);		// client가 접속했는지 체크하는 용도
		
			// 수신대기
			while(true) {
				System.out.println("수신 대기 중");
				socket = serverSocket.accept(); 		// 누군가 들어올 때까지 대기상태
				System.out.println("접속IP: "+ socket.getInetAddress());
				
				// 누군가 접속해서 메시지를 보내면
				is = socket.getInputStream();
				ois = new ObjectInputStream(is);
				
				os = socket.getOutputStream();
				oos = new ObjectOutputStream(os);
				
				// 메시지 수신 완료
				msg = (String)ois.readObject();
				System.out.println("클라이언트: " + msg);
				
				String respon = "서버가 준 메시지: " + msg;
				oos.writeObject(respon);
				
				socket.close(); 		// 연결을 종료
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

class MyClient {
	// 들어오는 메시지(수신)
	InputStream is;
	ObjectInputStream ois;
	// 나가는 메시지(송신)
	OutputStream os;
	ObjectOutputStream oos;
	
	// 메시지를 직접적으로 처리할 소켓을 추가생성
	Socket socket;
	String msg;
	Scanner sc = new Scanner(System.in);		// 콘솔 입력을 위해(임시)
	
	public void go(String ip, int port) {
		try {
			socket = new Socket(ip, port);		// 서버에 접속
			// 메시지를 내보낼 준비(송신준비)
			os = socket.getOutputStream();
			oos = new ObjectOutputStream(os);
			
			// 메시지를 받을 준비(수신준비)
			is = socket.getInputStream();
			ois = new ObjectInputStream(is);
			
			// 소켓통신
			System.out.println("보낼 메시지>> ");
			msg = sc.nextLine();
			oos.writeObject(msg); 		// 메시지 송신
			
			String respon = (String)ois.readObject();
			System.out.println(respon);
			
			socket.close(); 	// 소켓 연결을 끊는다
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

4. URL

- 대표적인 통신방식

  • TCP/IP: 먼저 서로 연결을 하고 메시지를 주고받음(비교적 안정적, 서버 과부하 우려, 일반적으로 많이 쓰임), Socket
  • UDP: 받든 말든 상관없이 일단 보낸다(방송, 브로드캐스트, 상대의 접속여부에 관계없이 송신), 연결유지x,                            DatagramSocket
  • HTTP: 웹 전용 통신, URL, 연결유지x
  • RestAPI: HTTP통신에서 정해진 규격에 맞춰 통신하는 관례

- 웹사이트에서 Html 코드 읽어오기(네이버 영화순위)

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;

public class URL2 {
	public static void main(String[] args) {
		MyURLEx m = new MyURLEx();
		m.go("https://movie.naver.com/movie/sdb/rank/rmovie.naver");
	}
}

class MyURLEx {
	InputStream is = null;
	InputStreamReader isr = null;
	BufferedReader br = null;
	URL url = null;
	String str = null;
	ArrayList<String> parseArray = new ArrayList<>();
	
	public void go(String address) {
		try {
			url = new URL(address);
			is = url.openStream();
			isr = new InputStreamReader(is, "UTF-8");
			br = new BufferedReader(isr);
			
			// 버퍼리더를 문자열로 변경(한줄씩 줄바꾸면서)
			while((str = br.readLine()) != null) {		// str에 먼저 한줄씩 담고 null과 같은지 비교.(br.readLine(): 한줄씩 읽기)
				// 내가 원하는 문자열을 찾는다
				if(str.contains("<a href=\"/movie/bi/mi/basic.naver?code=") && !(str.contains("onclick"))) {
					String parse = str.substring(str.indexOf("title=")+7, str.indexOf("\">")+0);
					parseArray.add(parse);		// 파싱한 문자열을 ArrayList에 저장
				}
				
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			try {
				isr.close();
				br.close();
				is.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		for(int i=0; i<parseArray.size();i++) {
			System.out.println((i+1)+"위. "+parseArray.get(i));
		}
	}
}