본문 바로가기

JAVA

240103 Java

금일 수업 내용 : Thread

 

package com.poseidon.thread;
// 24-01-03
// 남은 것 : Thread, IO, Net, GUI
// 이후, 프로젝트 제작 (Java, DB 중 택)

/*
 * 프로세스 : 운영체제에서는 실행 중인 하나의 어플리케이션을 프로세스라고 함
 *          사용자가 애플리케이션을 실행하면 운영체제로부터 실행에 필요한 메모리를 할당받아
 *          애플리케이션의 코드를 실행하는 것이 프로세스
 * 스레드 : 운영체제는 두가지 이상의 작업을 동시에 처리하는 멀티 태스킹을 할 수 있도록
 *         CPU 및 메모리 자원을 프로세스마다 적잘히 할당하고 병렬로 실행
 *         
 * 스레드 생성과 실행
 *  1. Runnable 인터페이스를 구현하는 방법
 *  
 *  2. Thread 클래스를 상속받는 방법
 *  
 *  두가지 방법인 이유
 *   - 다른 클래스가 상속 중인 경우 Thread 클래스를 상속받지 못함. 이런 경우를 대비하여
 *     인터페이스 Runnable 이 만들어져 있음 (Thread 클래스를 상속하는게 편함)
 *  
 *  실행은 start() 로 실행
 */
public class ThreadEx extends Thread{ // Thread 클래스 상속
  @Override
  public void run() {
    System.out.println("Thread 시작");
  }
  
  public static void main(String[] args) {
    ThreadEx th01 = new ThreadEx(); // 객체 생성
    th01.start(); // Thread 는 start() 로 실행
  }
}

 

여러 개의 Thread 실행해보기

package com.poseidon.thread;

public class Thread02 extends Thread{
  int seq;
  
  public Thread02(int seq) {
    this.seq = seq;
  }
  
  @Override
  public void run() {
    System.out.println(this.seq + " Thread 시작");
    try { // sleep 은 오류가 발생할 수 있어 try/catch 해야 함
      Thread.sleep(1000); // = 1000 밀리초 = 1 초
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    System.out.println(this.seq + " Thread 종료");
  }
  public static void main(String[] args) {
    System.out.println("main 메소드 시작");
    for (int i = 0; i < 3; i++) {
      Thread02 th02 = new Thread02(i);
      th02.start();
    }
    System.out.println("main 메소드 종료");
  }
}

 

실행 결과

main 이 종료되었으나 종료되지 않은 Thread 는 끝까지 유지되는 모습

 

Join 사용해보기

package com.poseidon.thread;

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

public class Thread03 extends Thread {
  int seq;

  public Thread03(int seq) {
    this.seq = seq;
  }

  @Override
  public void run() {
    System.out.println(this.seq + " Thread 시작");

    try {
      Thread.sleep(1000);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }

    System.out.println(this.seq + " Thread 종료");
  }

  public static void main(String[] args) {
    System.out.println("main 시작");
    List<Thread> tList = new ArrayList<Thread>();
    
    for (int i = 0; i < 3; i++) {
      Thread03 th03 = new Thread03(i);
      th03.start();
      tList.add(th03);
    }
    
    for (Thread thread : tList) {
      try {
        thread.join();
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
    
    System.out.println("main 종료");
  }
}

 

실행 결과 :

main 실행, Thread 가 모두 종료 된 후에 main 이 종료

 

Runnable 인터페이스를 구현하여 만들기

package com.poseidon.thread;

import java.util.ArrayList;

class A {
}
// 다른 클래스를 상속하여 Thread 를 상속하지 못할 때 사용
public class Thread04 extends A implements Runnable {
  int seq;

  public Thread04(int seq) {
    this.seq = seq;
  }

  @Override
  public void run() {
    System.out.println(this.seq + " Thread 시작");

    try {
      Thread.sleep(1000);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }

    System.out.println(this.seq + " Thread 종료");
  }

  public static void main(String[] args) {
    System.out.println("main 실행");
    ArrayList<Thread> tList = new ArrayList<Thread>();

    for (int i = 0; i < 10; i++) {
      Thread t = new Thread(new Thread04(i));
      // t 의 생성자로 Runnable 을 구현한 객체를 넘김
      t.start();
      tList.add(t);
    }

    for (int i = 0; i < tList.size(); i++) {
      Thread t = tList.get(i);
      try {
        t.join();
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }

    System.out.println("main 종료");
  }
}

 

Queue 와 Stack

package com.poseidon.coll;

import java.util.Stack;

/*
 * 선입선출 First In, First Out : FIFO / ex) 프린터 사용
 * 후입선출 Last In, First Out : LIFO / ex) 인터넷 앞으로 가기, 뒤로 가기
 */

class Coin {
  private int value;

  public Coin(int value) {
    this.value = value;
  }

  public int getValue() {
    return value;
  }
}

public class Stack01 {
  public static void main(String[] args) {
    Stack<Coin> coinBox = new Stack<Coin>();
    
    coinBox.push(new Coin(100));
    coinBox.push(new Coin(50));
    coinBox.push(new Coin(500));
    coinBox.push(new Coin(10));
    
    while(!coinBox.isEmpty()) {
      Coin coin = coinBox.pop();
      System.out.println("동전 : " + coin.getValue());
    }
  }
}

 

Queue

package com.poseidon.coll;

import java.util.LinkedList;
import java.util.Queue;

class Message {
  public String command;
  public String to;

  public Message(String command, String to) {
    this.command = command;
    this.to = to;
  }
}

public class Queue01 {
  public static void main(String[] args) {
    Queue<Message> messageQueue = new LinkedList<>();

    messageQueue.offer(new Message("sendMail", "홍길동"));
    messageQueue.offer(new Message("sendSMS", "김길동"));
    messageQueue.offer(new Message("sendKaKaoTalk", "최길동"));

    while (!messageQueue.isEmpty()) {
      Message message = messageQueue.poll(); // 큐에서 1 개씩 꺼냄

      switch (message.command) {
        case "sendMail":
          System.out.println(message.to + "님께 메일을 보냅니다");
          break;
        case "sendSMS":
          System.out.println(message.to + "님께 문자를 보냅니다");
          break;
        case "sendKaKaoTalk":
          System.out.println(message.to + "님께 카카오톡을 보냅니다");
          break;
      }
    }
  }
}

 

Input, Output

package com.poseidon.io;

import java.io.FileOutputStream;
import java.io.OutputStream;

public class IO01 {
  public static void main(String[] args) throws Exception {
    OutputStream os = new FileOutputStream("c:/temp/test.txt");
    
    byte a = 97;
    byte b = 98;
    byte c = 99;
    
    os.write(a);
    os.write(b);
    os.write(c); // ASCII CODE 로 값 전달
    
    os.flush(); // abc 출력
    os.close();
  }
}

 

배열을 담아 보내기

package com.poseidon.io;

import java.io.FileOutputStream;
import java.io.OutputStream;

public class IO02 {
  public static void main(String[] args) throws Exception{
    OutputStream os = new FileOutputStream("c:/temp/test2.txt");
    
    byte[] arr = new byte[] {66, 69, 72, 72, 79};
    // 1byte = 8bit
    
    os.write(arr);
    
    os.flush(); // BEHHO 전송
    os.close();    
  }
}

 

파일 읽기

package com.poseidon.io;

import java.io.FileInputStream;
import java.io.InputStream;

public class IO03 {
  public static void main(String[] args) throws Exception{
    InputStream is = new FileInputStream("c:/temp/test.txt");
    // abc 가 들어있는 문서 파일
    while (true) {
      int data = is.read(); // 출력할 값이 없으면 -1 대입
      if (data == -1) {
        break;
      }
      System.out.println(data);
    }
    is.close();
  }
}

 

파일 읽기 두번째

package com.poseidon.io;

import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Arrays;

public class IO04 {
  public static void main(String[] args) throws Exception {
    InputStream is = new FileInputStream("c:/temp/test.txt");
    // abc 가 들어있는 txt 파일
    byte[] arr = new byte[2];

    while (true) {
      int readByteNum = is.read(arr);
      // .read() : 읽은 메소드 개수 반환
      if (readByteNum == -1) { // 읽을 게 없으면 -1
        break;
      }
      for (int i = 0; i < readByteNum; i++) {
        System.out.println((char) arr[i]);
      } // 메모장에 적힌 값을 ascii code 로 입력받는데, 그걸 다시 문자로 변환
      System.out.println(Arrays.toString(arr));
      System.out.println(readByteNum + " : " + Arrays.toString(arr));
    }
    is.close();
  }
}

 

문자열 저장하기

package com.poseidon.io;

import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;

public class IO05 {
  public static void main(String[] args) throws Exception {
    FileOutputStream fos = new FileOutputStream("c:/temp/test5.txt");
    Writer writer = new OutputStreamWriter(fos);
//    Writer writer = new OutputStreamWriter(new FileOutputStream("c:/temp/test6.txt"));
    
    writer.write("문자열을 저장합니다.");
    writer.flush();
    writer.close();
  }
}

 

어느 디렉토리에 들어있는 파일 형태와 정보 확인하기

package com.poseidon.io;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

public class IO06 {
  public static void main(String[] args) {
    File dir = new File("c:/temp/images");
    
    if (dir.exists() == false) {
      dir.mkdir(); // 새로운 폴더를 생성
      // dir.mkdirs() : 경로상에 없는 모든 폴더를 생성
      // createNewFile() : 새로운 파일을 생성
    }
    
    File temp = new File("c:/temp");
    File contents[] = temp.listFiles();
    System.out.println(Arrays.toString(contents));
    
    System.out.println("시간\t\t\t형태\t\t크기\t이름");
    System.out.println("----------------------------------------------------");
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd a HH:mm");
    for (File file : contents) {
      System.out.print(sdf.format(new Date(file.lastModified())));
      if(file.isDirectory()) {
        System.out.println("\t<DIR>\t\t\t" + file.getName());
      } else {
        System.out.println("\t\t\t" + file.length() + "\t" + file.getName());
      }
//      System.out.println();
    }
  }
}

 

Inner 클래스

헷갈리긴 하지만.. 

package com.poseidon.inner;

// 중첩 클래스 : 클래스 속 클래스
/* Inner Class 내부 클래스
 * 클래스 내부에 선언된 클래스 : 두 클래스가 서로 긴밀한 관계
 * 
 * 장점
 * 내부 클래스에서 외부 클래스의 멤버들을 쉽게 접근할 수 있음
 * 캡슐화, 코드의 복잡성을 줄여줌
 * 
 * 보통의 클래스
 * class A{}
 * class B{}
 * 
 * 내부 클래스는 두 클래스가 긴밀하고, 내부 클래스는 잘 사용되지 않는 것
 * class A { class B {} }
 * 
 * 종류
 * static(정적) 클래스 : 외부 클래스의 멤버 변수 위치에 선언, 외부 클래스의 스태틱 멤버처럼 다뤄짐
 *                    주로 외부 클래스의 스태틱 멤버, 특히 스태틱 메소드에서 사용 할 목적으로 선언
 * 
 * 멤버 클래스 : 외부 클래스의 멤버 변수 위치에 선, 외부 클래스의 인스턴스 멤버처럼 사용
 *            주로 외부 클래스의 인스턴스 멤버들과 관련된 작업에 활용
 *            
 * 지역 클래스 : 외부 클래스의 메소드나 초기화 블럭 안에서 선언, 선언된 영역 내부에서만 사용 가능
 * 
 * 익명 클래스 : 클래스 선언과 객체 생성을 동시에 하는 이름이 없는 클래스(일회용)
 */
class A {
  public A() {
    System.out.println("A 객체가 생성됨");
  }
  class B {
    int field1;
    // static int field2; static 사용 X
    public B() {
      System.out.println("B 객체가 생성됨");
    }
    public void methodB() { }
    // public static void methodB2() {} static 사용 X
  }
  static class C { // 정적 멤버 클래스
    int field1;
    static int field2;
    public C() {System.out.println("C 객체가 생성됨");}
    public void methodC() {}
    public static void methodC2() {}
  }
  public void methodA() { // class A 의 메소드
    // 로컬 영역
    int num = 10; // 지역 변수
    class D { // 지역 클래스
      int field1;
      public D() {
        System.out.println("D 객체가 생성됨");
      }
      public void methodD() {}
      // public static void methodD2() {} static 사용 X
    } // Class D 의 마지막
    D d = new D(); // 객체 생성
    d.field1 = 3;
    d.methodD(); // D 객체의 필드 및 메소드 접근 가능
  } // methodA 의 마지막
}

public class Inner01 {
  public static void main(String[] args) {
    A a = new A();
    A.B b = a.new B();
    b.field1 = 1;
    b.methodB();
    A.C c = new A.C();
    c.field1 = 1;
    A.C.field2 = 2; // static
    c.methodC();
    A.C.methodC2(); // static
    a.methodA(); // 메소드가 실행되며 D 객체 생성됨
  }
}

 

2번 Inner 와 3번 Inner 가 왔다갔다 함

package com.poseidon.inner;

class Button {
  OnClickListener listener;
  
  void setOnClickListener(OnClickListener listener) {
    this.listener = listener;
  }
  
  void touch() {
    listener.onClick();
  }
  
  static interface OnClickListener {
    void onClick();
  }
}

public class Inner02 implements Button.OnClickListener{
  @Override
  public void onClick() {
    
  }
  public static void main(String[] args) {
  
  }
}

 

package com.poseidon.inner;

public class Inner03 {
  public static void main(String[] args) {
    Button button = new Button();
    
    button.setOnClickListener(new Inner02());
    button.touch();
  }
}

 

클래스의 메소드를 사용할 곳에서만 오버라이드하여 사용하기

package com.poseidon.inner;
/*
 * 클래스 명이 없는 클래스, 선언과 동시에 인스턴스 생성을 하나로 통합한 클래스
 * 클래스를 인수값으로 사용하는 클래스, 객체를 한 번만 사용할 경우 사용
 * 
 * 클래스의 선언부가 없기 때문에 이름이 없음 = 생성자를 가질 수 없음
 * 슈퍼 클래스의 이름이나 구현할 인터페이스를 구현하거나 둘 이상의 인터페이스를 구현할 수 없음
 * 오직 하나의 클래스를 상속받거나 하나의 인터페이스만 구현 가능
 * 
 * 코드 블럭에 클래스를 선언하는 점만 제외하고는 생성자를 호출하는 것과 동일
 * 객체를 구성하는 new 문장 뒤에 클래스의 블록 {}, 메소드를 구현한 블록이 있고 블록 끝 세미콜론이 붙음
 * new 뒤에 오는 생성자명이 기존 클래스명이면 익명 클래스, 자동으로 클래스의 하위 클래스가 됨
 * 
 * 인터페이스인 경우에 인터페이스를 상속하는 부모 클래스가 Object가 됨
 */

class Anonymous {
  public void print() {
    System.out.println("출력");
  }
}
public class Inner04 {
  public static void main(String[] args) {
    Anonymous any = new Anonymous() {
      @Override
      public void print() {
        System.out.println("프린트");
      }
    };
    any.print(); // "프린트" 출력
  }
}

 

 

'JAVA' 카테고리의 다른 글

240216 JAVA 옵셔널 공부하기  (0) 2024.02.16
240111 홈페이지 만들기  (2) 2024.01.11
231227 Java  (0) 2023.12.27
231226 Java  (0) 2023.12.26
231222 Java  (0) 2023.12.22