Java 12일차 : 스레드, 동기화, 네트워크, 채팅프로그램

스레드

멀티태스킹

  • 프로세스 : 운영체제에서 실행중인 하나의 프로그램

  • 멀티 프로세스 : 두 개 이상의 프로세스가 실행되는 것

  • 멀티 태스킹 : 두 개 이상의 프로세스를 실행하여 일을 처리하는 것

멀티스레드

  • 스레드 : 프로세스 내에서 실행되는 세부 작업 단위

  • 멀티 스레드 : 하나의 프로세스에서 여러 개의 스레드가 병행적으로 처리되는 것

자바에서 멀티스레드를 구현하는 방법은 2가지가 있다

  • 클래스 Thread를 상속 받는 방법
  • 인터페이스 runnable 을 구현하는 방법

위의 클래스 또는 인터페이스가 가진 run 메서드를 오버라이드한다. run 메서드호출은start

스레드의 생명 주기

스레드는 Thread 객체가 생성되면 생명주기를 갖게 되는데 크게 5가지로 나누게 된다.

  • New – 스레드가 만들어진 상태.
  • Runnable – 스레드 객체가 생성된 후에 start() 메서드를 호출하면 Runnable 상태로 이동하게 된다.
  • Running – Runnable 상태에서 스레드 스케줄러에 의해 Running 상태로 이동하게 된다.
  • Blocked – 스레드가 다른 특정한 이유로 Running 상태에서 Blocked 상태로 이동하게 된다.
  • Dead – 스레드가 종료되면 그 스레드는 다시 시작할 수 없게 된다.
반환형 메서드 설명
static void sleep(long mills) mills에 지정된 시간만큼 대기
String getName() 스레드의 이름 반환
void setName(String name) 스레드 이름 지정
void start() 스레드 시작
int getPriority() 스레드의 우선순위 반환
void setPriority(int p) 스레드의 우선순위 지정
void join() join()메서드를 호출한 스레드가 종료시까지 현재 스레드 대기
static void yield() 수행중인 스레드 중 우선순위가 같은 다른 스레드에게 제어권 넘김
static Thread currentThread() 현 수행되는 스레드 객체 리턴
package test.day0418;

// 스레드를 사용하지 않는 예(하나의 스레드)
public class ThreadEx1 {
  String name;
  int num;
  public ThreadEx1(String name, int num) {
    this.name = name;
    this.num = num;
  }

  public void run() {
    for(int i=1 ; i <= num ; i++) {
      System.out.println(name + " => " + i);
    }
  }
  public static void main(String[] args) {
    // TODO Auto-generated method stub
    ThreadEx1 th1 = new ThreadEx1("one", 300);
    ThreadEx1 th2 = new ThreadEx1("two", 300);
    ThreadEx1 th3 = new ThreadEx1("three", 300);
    //run메서드 호출
    th1.run();
    th2.run();
    th3.run();
  }
}
package test.day0418;

//ex1번을 복사하여 스레드를 상속받는 클래스로 만들자 
public class ThreadEx2 extends Thread {
  String name;
  int num;
  public ThreadEx2(String name, int num) {
    this.name = name;
    this.num = num;
  }
  //스레드 상속받을 시 이건 오버라이드 메서드가 됨 
  @Override
  public void run() {
    for(int i=1 ; i <= num ; i++) {
      System.out.println(name + " => " + i);
    }
  }
  public static void main(String[] args) {
    // TODO Auto-generated method stub
    ThreadEx2 th1 = new ThreadEx2("one", 300);
    ThreadEx2 th2 = new ThreadEx2("two", 300);
    ThreadEx2 th3 = new ThreadEx2("three", 300);
    //스레드의 run호출은 start이다.
    th1.start(); //runnable 상태에서 스케줄러에 의해 하나씩 running 상태가 된다.
    th2.start();
    th3.start();
  }
}
package test.day0418;

//ex2를 Runnable로 상속받는(구현하는) 클래스로 구현해보자 
public class ThreadEx3 implements Runnable {
  String name;
  int num;
  public ThreadEx3(String name, int num) {
    this.name = name;
    this.num = num;
  }
  //스레드 상속받을 시 이건 오버라이드 메서드가 됨 
  @Override
  public void run() {
    for(int i=1 ; i <= num ; i++) {
      System.out.println(name + " => " + i);
      try {
        Thread.sleep(300);
      } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
    }
  }
  public static void main(String[] args) {
    // TODO Auto-generated method stub
    //runnable 인터페이스를 구현한 클래스를 생성한것에 불과 
    ThreadEx3 ex1 = new ThreadEx3("one", 300);
    ThreadEx3 ex2 = new ThreadEx3("two", 300);
    ThreadEx3 ex3 = new ThreadEx3("three", 300);
    //runnable로 구현할 경우에는 쓰레드를 생성해줘야 한다.
    Thread th1 = new Thread(ex1);
    Thread th2 = new Thread(ex2);
    Thread th3 = new Thread(ex3);
    //스레드의 run호출은 start이다.
    th1.start(); //runnable 상태에서 스케줄러에 의해 하나씩 running 상태가 된다.
    th2.start();
    th3.start();
  }
}

동기화

  • 여러 스레드가 동시에 특정 메소드에 접근해서 처리하다보면 문제가 발생할 수 있다.

  • 이 때 특정 스레드가 해당 메서드를 다 처리하기 전까지는 다른 스레드는 기다려야하며 처리가 끝날때까지 접근을 못하도록 하려면 이렇게..

public synchronized void hello(){
}

네트워크

TCP

  • Transmission Control Protocol
  • 신뢰할 수 있는 프로토콜로서 , 데이터를 상대측까지 제대로 전달했는지 확인 메시지를 주고 받음으로써 데이터의 송수신 상태를 점검한다

UDP

  • User Datagram Protocol
  • 신뢰할 수 없는 프로토콜로서, 데이터를 보내기만 하고 확인 메시지를 주고 받지 않기 때문에 제대로 전달했는지 확인하지 않는다.
  • TCP가 전화라면 UDP는 편지같은 개념

InetAddress

  • InetAddress 클래스는 IP 주소를 표현한 클래스이다.
  • 자바에서는 모든 IP 주소를 InetAddress 클래스를 사용한다.
package test.day0418;

import java.net.InetAddress;
import java.net.UnknownHostException;

public class InetAddressEx5 {

  public static void main(String[] args) {
    // TODO Auto-generated method stub
    try {
      InetAddress myAddr = InetAddress.getLocalHost();
      System.out.println("local ip: " + myAddr.getHostAddress());
      System.out.println("local name: " + myAddr.getHostName());
    }catch(UnknownHostException e) {
      e.printStackTrace();
    }
    //String hostName = "www.naver.com";
    String hostName = "www.google.com";
    try {
      InetAddress addr[] = InetAddress.getAllByName(hostName);
      for(InetAddress ia:addr) {
        System.out.println("name: " + ia.getHostName());
        System.out.println("ip: " + ia.getHostAddress());
      }
    } catch (UnknownHostException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }
}
package test.day0418;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;

//네이버의 소스 읽어오기
public class URLEx6 {

  public static void main(String[] args) {
    // TODO Auto-generated method stub
    String hostName = "http://www.google.com";
    try {
      URL url = new URL(hostName);
      InputStream is = url.openStream();
      BufferedReader br = new BufferedReader(new InputStreamReader(is));
      while(true) {
        String line = br.readLine();
        if(line == null)
          break;
        System.out.println(line);
      }
    } catch (Exception e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }
}

ServerSocket

  • 서버에서 접속하는 클라이언트를 허용하기 위한 클래스
  • 허용을 하게되면 양방향 통신을 할수 있는 Socket이 생성된다
  • 자바프로그램은 소켓이라는 개념을 통해서 네트워크 통신을 한다
package test.day0418;

import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;

public class ServerSocketEx7 extends Thread {

  ServerSocket server;

  public ServerSocketEx7() {

    try {
      server = new ServerSocket(7000);
      System.out.println("server socket successful");
    } catch (IOException e) {

      System.out.println("서버소켓 생성실패 ");
    }

  }

  @Override
  public void run() {
    while(true) {
      try {
        Socket socket = server.accept();
        InetAddress inet = socket.getInetAddress();
        System.out.println("접속한 컴퓨터 이름: " + inet.getHostName());
        System.out.println("접속한 컴퓨터의 ip: " + inet.getHostAddress());
        System.out.println("--------------------------------------");

      } catch (IOException e) {
        System.out.println("클라이언트 서버에 접속실패 " +e.getMessage());
      } 
    }

  }

  public static void main(String[] args) {
    // TODO Auto-generated method stub
    ServerSocketEx7 ss = new ServerSocketEx7();
    ss.start(); //run method호출 
  }
}
package test.day0418;

import java.io.IOException;
import java.net.Socket;
import java.util.Scanner;

public class ClientSocketEx7 {

  public static void main(String[] args) {
    // TODO Auto-generated method stub

    Socket socket = null;
    Scanner sc = new Scanner(System.in);
    String lastip;
    System.out.println("접속할 서버의 마지막 ip숫자를 입력하세요.");
    lastip = sc.nextLine();
    String serverip = "192.168.0." + lastip;

    try {
      socket = new Socket(serverip, 7000);
      System.out.println("서버 접속 성공");
    } catch (IOException e) {

      System.out.println("서버 접속 실패 ");
    }
  }
}

채팅 프로그램 만들기

package test.day0418;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Vector;

public class ServerSocketEx8 extends Thread {

  ServerSocket server;
  Vector<ConnectClient> list;

  public ServerSocketEx8() {

    try {
      server = new ServerSocket(7000);
      System.out.println("server socket successful");

      //클라이언트 정보를 담을 벡터 생성
      list = new Vector<ConnectClient>();

    } catch (IOException e) {
      System.out.println("서버소켓 생성실패 ");
    }

  }

  @Override
  public void run() {
    while(true) {
      try {
        Socket socket = server.accept();
        InetAddress inet = socket.getInetAddress();
        System.out.println("접속한 컴퓨터 이름: " + inet.getHostName());
        System.out.println("접속한 컴퓨터의 ip: " + inet.getHostAddress());
        System.out.println("--------------------------------------");


        //접속한 클라이언트를 생성 후 벡터에 담아서 서버가 가지고 있어야만 한다.
        ConnectClient cc = new ConnectClient(socket);
        list.add(cc);
        cc.start();//내부클래스의 run메서드 호출 

      } catch (IOException e) {
        System.out.println("클라이언트 서버에 접속실패 " +e.getMessage());
      } 
    }
  }

  class ConnectClient extends Thread{

    Socket socket;
    BufferedReader br;
    PrintWriter pw;

    public ConnectClient(Socket socket) {
      this.socket = socket;

      //io클래스 생성

      try {
        br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        pw = new PrintWriter(socket.getOutputStream());

      } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
    }



    @Override
    public void run() {
      while(true) {
        //클라이언트가 보내는 메세지 읽기
        try {
          String msg = br.readLine();
          System.out.println(msg);
        } catch (IOException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
      }
    }

  }

  //클라이언트와 대화를 할 내부클래스 - 스레드여야 한다.
  public static void main(String[] args) {
    // TODO Auto-generated method stub
    ServerSocketEx8 ss = new ServerSocketEx8();
    ss.start(); //run method호출 

  }
}
package test.day0418;

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

public class ClientSocketEx8 {

  public static void main(String[] args) {
    // TODO Auto-generated method stub

    Socket socket = null;
    Scanner sc = new Scanner(System.in);
    String lastip;

    BufferedReader br = null;
    PrintWriter pw = null;

    System.out.println("접속할 서버의 마지막 ip숫자를 입력하세요.");
    lastip = sc.nextLine();

    String serverip = "192.168.0." + lastip;

    try {
      socket = new Socket(serverip, 7000);
      System.out.println("서버 접속 성공");

      try {
        br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        pw = new PrintWriter(socket.getOutputStream());


      } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }

      while(true) {
        System.out.println("메세지입력 ");
        String msg = sc.nextLine();
        if(msg.equalsIgnoreCase("q"))
          break;

        pw.write(msg + "\n");
        pw.flush();

      }
    } catch (IOException e) {
      System.out.println("서버 접속 실패 ");
    }
  }
}

Categories:

Updated:

Comments