Akashic Records

Java Threads 본문

오래된글/Java

Java Threads

Andrew's Akashic Records 2018. 4. 7. 23:09
728x90

Chap 1 쓰레드의 소개


멀티쓰레딩의 개요

1. 프로그램 내의 쓰레드들 중 하나의 시작 지점은 main() 메쏘드 이다.

2. 쓰레드가 수행하는 메쏘드 내의 지역 변수는 다른 쓰레드에서 절대로 접근할 수 없다. 이 지역 변수는 철저하게 보호된다.

3. 반면에 객체와 인스턴스 변수는 자바 프로그램 내의 쓰레드간 공유가 가능하다.


Chap 2 자바 쓰레딩 API


간단한 쓰레드 – 1

public class OurClass extends Thread {

   private String message = "";

   public OurClass(String message){

       super(message+" thread");

       this.message = message;

   }

   public void run() {

       for (int I = 0; I < 10; I++) {

           System.out.println(message);

           System.out.println(getName()+" : "+Thread.currentThread().activeCount());

           System.out.println(Thread.currentThread().toString());

           Thread ta[] = new Thread[Thread.activeCount()];

           int n = Thread.enumerate(ta);

           for(int i = 0; i < n; i++) {

               System.out.println("Thread "+i+" is "+ta[i].getName());

           }

       }

   }

}

import javax.swing.JApplet;

public class OurApplet extends JApplet {

   public void init() {

       OurClass oc1 = new OurClass("hello!!~~1");

       OurClass oc2 = new OurClass("hello!!~~2");

       OurClass oc3 = new OurClass("hello!!~~3");

       oc1.start();

       oc2.start();

       oc3.start();

   }

}


간단한 쓰레드 - 2

import java.applet.*;

import java.awt.*;

public class Animate extends Applet implements Runnable {

   int count, lastcount;

   Image pictures[];

   Thread timer;

   public void init() {

       lastcount = 10; count = 0;

       pictures = new Image[10];

       MediaTracker tracker = new MediaTracker(this);

       for (int a = 0; a < lastcount; a++) {

           pictures[a] = getImage (

               getCodeBase(), new Integer(a).toString()+".jpg");

           tracker.addImage(pictures[a], 0);

       }

       tracker.checkAll(true);

   }

   public void start() {

       if (timer == null) {

           timer = new Thread(this);

           timer.start();

       }

   }

   public void paint(Graphics g) {

       g.drawImage(pictures[count++], 0, 0, null);

       if (count == lastcount) count = 0;


   }

   public void run() {

       while (isActive()) {

           try {

               repaint();

               Thread.sleep(1000);

           } catch (Exception e) {}

       }

       timer = null;

   }   

}



간단한 쓰레드 - 3

// ftp 연결 코넥션을 가지고 대기하는 프로그램

package thread.net;

import java.awt.Frame;

import java.awt.event.WindowAdapter;

import java.awt.event.WindowEvent;

import javax.swing.UIManager;

import java.awt.Dimension;

import java.awt.Toolkit;

public class FTPKeeperMain  {

   public FTPKeeperMain() {

       Frame frame = new FTPKeeperFrame();

       Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();

       Dimension frameSize = frame.getSize();

       if (frameSize.height > screenSize.height) {

           frameSize.height = screenSize.height;

       }

       if (frameSize.width > screenSize.width) {

           frameSize.width = screenSize.width;

       }

       frame.setLocation((screenSize.width - frameSize.width) / 2, (screenSize.height - frameSize.height) / 2);

       frame.addWindowListener(new WindowAdapter() {

               public void windowClosing(WindowEvent e) {

                   System.exit(0);

               }

           });

       frame.setVisible(true);

   }

   public static void main(String[] args) {

       try {

           UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());

       } catch(Exception e) {

           e.printStackTrace();

       }

       new FTPKeeperMain();

   }

}

package thread.net;

import javax.swing.JFrame;

import java.awt.Dimension;

import javax.swing.JTextField;

import java.awt.Rectangle;

import javax.swing.JButton;

import javax.swing.JScrollPane;

import javax.swing.JTextPane;

import javax.swing.BorderFactory;

import javax.swing.ActionMap;

import java.awt.event.ActionListener;

import java.awt.event.ActionEvent;

public class FTPKeeperFrame extends JFrame  {

   private JTextField ip = new JTextField();

   private JTextField pwd = new JTextField();

   private JTextField port = new JTextField();

   private JTextField term = new JTextField();

   private JTextField id = new JTextField();

   private JButton startButton = new JButton();

   private JButton stopButton = new JButton();

   private JScrollPane jScrollPane1 = new JScrollPane();

   private JTextPane messagePane = new JTextPane();

   private ActionMap actionMap1 = new ActionMap();

   private javaFtp jftp;

   


   public FTPKeeperFrame() {

       try {

           jbInit();

       } catch(Exception e) {

           e.printStackTrace();

       }

   }

   private void jbInit() throws Exception {

       this.getContentPane().setLayout(null);

       this.setSize(new Dimension(432, 428));

       this.setTitle("FTPConnetion Keeper");

       ip.setBounds(new Rectangle(20, 25, 135, 40));

       ip.setBorder(BorderFactory.createTitledBorder("IP"));

       ip.setText("164.125.167.33");

       pwd.setBounds(new Rectangle(170, 140, 135, 40));

       pwd.setBorder(BorderFactory.createTitledBorder("PWD"));

       pwd.setText("movie");

       port.setBounds(new Rectangle(20, 85, 135, 40));

       port.setBorder(BorderFactory.createTitledBorder("PORT"));

       port.setText("21");

       term.setBounds(new Rectangle(170, 85, 135, 40));

       term.setBorder(BorderFactory.createTitledBorder("TERM (SEC)"));

       term.setText("10");

       id.setBounds(new Rectangle(20, 140, 135, 40));

       id.setBorder(BorderFactory.createTitledBorder("ID"));

       id.setText("pk");

       startButton.setText("START");

       startButton.setBounds(new Rectangle(320, 85, 80, 40));

       startButton.addActionListener(new FTPKeeperFrame_startButton_actionAdapter(this));

       stopButton.setText("STOP");

       stopButton.setBounds(new Rectangle(320, 140, 80, 40));

       stopButton.setEnabled(false);

       stopButton.addActionListener(new FTPKeeperFrame_stopButton_actionAdapter(this));

       jScrollPane1.setBounds(new Rectangle(20, 220, 380, 150));

       jScrollPane1.getViewport().add(messagePane, null);

       this.getContentPane().add(jScrollPane1, null);

       this.getContentPane().add(stopButton, null);

       this.getContentPane().add(startButton, null);

       this.getContentPane().add(id, null);

       this.getContentPane().add(term, null);

       this.getContentPane().add(port, null);

       this.getContentPane().add(pwd, null);

       this.getContentPane().add(ip, null);

   }

   private void isUse(boolean used) {

       stopButton.setEnabled(!used);

       messagePane.setEnabled(!used);

       startButton.setEnabled(used);

       ip.setEnabled(used);

       port.setEnabled(used);

       term.setEnabled(used);

       id.setEnabled(used);

       pwd.setEnabled(used);

   }

   void startButton_actionPerformed(ActionEvent e) {

       isUse(false);

       jftp = new javaFtp(

                           ip.getText(),

                           Integer.parseInt(port.getText()),

                           Integer.parseInt(term.getText()),

                           id.getText(),

                           pwd.getText(),

                           messagePane);

       jftp.start();

   }

   void stopButton_actionPerformed(ActionEvent e) {

       jftp.isChecked = false;

       while(jftp.isAlive()) {

           


       }

       isUse(true);

   }

}

class FTPKeeperFrame_startButton_actionAdapter implements ActionListener  {

   FTPKeeperFrame adaptee;

   FTPKeeperFrame_startButton_actionAdapter(FTPKeeperFrame adaptee) {

       this.adaptee = adaptee;

   }

   public void actionPerformed(ActionEvent e) {

       adaptee.startButton_actionPerformed(e);

   }

}

class FTPKeeperFrame_stopButton_actionAdapter implements ActionListener  {

   FTPKeeperFrame adaptee;

   FTPKeeperFrame_stopButton_actionAdapter(FTPKeeperFrame adaptee) {

       this.adaptee = adaptee;

   }

   public void actionPerformed(ActionEvent e) {

       adaptee.stopButton_actionPerformed(e);

   }

}

package thread.net;

import sun.net.ftp.*;

import javax.swing.*;

public class javaFtp extends Thread {

   FtpClient fc;

   JTextPane messagePane;

   String hostname;

   int port;

   int term;

   String username;

   String password;

   


   boolean isChecked = true;

   private boolean isconnected = false;

   public javaFtp(String hostname, int port, int term, String username, String password, JTextPane messagePane ) {

       this.hostname = hostname;

       this.port = port;

       this.term = term;

       this.username = username;

       this.password = password;

       this.messagePane = messagePane;

   }

   public void run() {

       while(isChecked) {

           if(!isconnected) {

               try {

                   fc = new FtpClient(hostname,port);

                   fc.login(username, password);

                   setMessage("Connection Sucssess!");

                   this.isconnected = true;

               } catch (java.io.IOException ioe) {

                   setMessage(ioe.toString());

               }

           } else {

               if(fc.serverIsOpen()) {

                   setMessage("FTP Connected");

               } else {

                   setMessage("FTP Closed");

                   this.isconnected = false;

               }

           }

           try{

               sleep(1000*term);

           } catch (Exception e){}

       }

   }

   private void setMessage(String message) {

       messagePane.setText(messagePane.getText()+message+" \n");

   }

}


Thread Method

  1. Thread() : 디폴트 생성자

  2. void run() : 반드시 오버라이드 해야하는 콜백 메쏘드

  3. void start() : 새로운 쓰레드를 생성하고 이 쓰레드 클래스에서 정의된 run() 메쏘드를 수행한다.

  4. static void sleep(long milliseconds/logn milliseconds, int nanoseconds) : 지정된 밀리세컨드 단위의 시간동안 슬립 상태에 빠져있게 한다.(ps : 모든 가상 머신은 근사 값으로 변경하여 적용한다.) 이는 쓰레드를 일정시간 blocked 상태로 만든다.

  5. void stop() : 이 메소드는 본질적으로 안전하지는 않습니다.

  6. final void resume() : 추천 되어 있지 않습니다. 이 메소드는 데드 록을 발생하기 쉽기 때문에 추천 되지 않습니다.

  7. final boolean isAlive() : 이 thread가 생존하고 있을지 어떨지를 판정 합니다.

  8. final void join() : 지정된 쓰레드가 작업 완료될 때까지 기다린다.

  9. String getName() : 쓰레드 인스턴스에 이름을 얻는다.

  10. static Thread currentThread() : 현재 수행되고 있는 쓰레드를 나타내는 쓰레드 객체를 리턴한다.

  11. static int enumerate(Thread threadArray[]) : 프로그램의 모든 쓰레드 객체들을 얻고 그 결과를 배열에 저장한다.

  12. static int activeCount() : 프로그램의 모든 쓰레드의 개수를 리턴한다.


Chap 3 동기화 기법

뮤텍스 락(Mutex lock) : 상호배제 락으로 알려져 있다. 많은 쓰레드 시스템이 이 형태의 락을 동기화를 위한 한 가지 방법으로 제공한다. 기본적으로, 한번에 하나의 쓰레드만 뮤텍스를 소유할 수 있다. 만약 두 개의 쓰레드가 뮤텍스를 얻으려고 시도하면, 하나의 쓰레드만 성공한다(synchronized). 다른 하나는 첫번째 쓰레드가 락을 해제할 때까지 대기해야 한다. 만약 첫번째 쓰레드가 락을 해제하면, 그때 두 번째 쓰레드가 그 락을 얻어 수행을 계속하게 된다. 자바에서는 시스템 내의 모든 객체에 락이 생성된다. 메쏘드가 동기화로 선언되면, 수행중인 쓰레드는 수행을 계속하기 위해서 그 객체에 할당된 락을 얻어야 한다. 매쏘드의 수행이 종료되면 자동적으로 락이 해제된다.


동기화 메쏘드와 동기화 블록 : 메쏘드 전체를 동기화시키는 것이 가장 간단하다. 그러나 동기화의 범위가 너무 넓으면 데드락에 빠질 수 있다. 또한 락이 불필요한 코드에서 락을 가지는 것은 효율적이지 못하다. 동기화 블록을 사용하는 것도 만약 너무 많은 락이 관련되어 있으면 문제를 일으킬 수 있다. 너무 많은 락을 얻으려고 시도하는 것도 데드락 조건에 빠질 수 있다. 또한 락을 얻거나 해제하는 것에는 오버해드가 있으므로, 코드의 몇 라인 후에 또 얻을 락을 해제하는 것도 바람직하지 못하다.


클래스 락과 클래스 객체 : 동기화된 정적 메쏘드가 호출됐을 때 시스템은 클래스 락을 얻는다. 사실 클래스 락과 같은 것은 실제로 존재하지 않는다. 동기화된 정적 메소드가 호출되면 시스템은 클래스 객체의 객체 락을 얻는다. 이는 클래스 락은 실제로는 해당되는 클래스 객체의 락을 의미한다는 것이다. 클래스 객체 락을 사용하는 정적 동기화 메쏘드와 동기화 블록을 모두 사용하면 혼란을 야기 할수 있다.


Chap 4 대기와 통지

  • public final void wait() : 다른 쓰레드가 이 Object 의 notify(), notifyAll() 메쏘드를 호출할 때 까지 현재의 쓰레드를 대기 시킵니다. 동기화된 메쏘드나 블록안에서 호출되어야 한다.

  • public final void notify() : 조건이 발생하기를 기다리고 있던 쓰레드에게 재개를 통지해 준다. 동기화된 메쏘드나 블록안에서 호출되어야 한다.

  • public final void notifyAll() : 다수의 쓰레드가 조건을 기다리고 있을 때, 존건이 발생한 객체에서 기다리고 있는 모든 쓰레드에게 통지해 준다. 이것은 Object 클래스의 메쏘드이고 반드시 동기화된 메쏘드나 블록 안에서 호출 되어야 한다.

  • wait(long) 과 sleep(logn)의 차이 : wait(long) 매쏘드는 특별한 이점을 가지고 있다. 그것은 락을 해제하고 다시 획득하는 것을 제외하고느 Thread 클래스의 sleep(long) 메쏘드와 비슷하게 동작한다는 것이다.


Chap 5 자바 쓰레드 스케줄링


  • 프로그램의 특성에 따른 분류

1. CPU 집중적인 프로그램 : 작업을 마치기 위해 많은 CPU 사이클을 요구하는 프로그램

2. I/O집중적인 프로그램 : I/O작업이 종료될 때까지 대기하는 시간이 많은 프로그램, 디스크, 네트워크로부터 데이터를 쓰거나 읽는 프로그램이거나 다른 프로그램과 통신하는 프로그램

3. 사용자와 대화형으로 작동하는 프로그램 : 사용자의 입력에 반응하여 작동하는 프로그램, 사용자가 특정한 명령을 내리면, 프로그램은 CPU 집중적이거나 I/O집중적인 작업에 들어간다. 작업이 끝나면 다시 다음 명령을 기다리는 구조가 일반적이다.


  • 자바 가상 머신상의 모든 쓰레드는 다음 4가지 상태 중에 하나이다.

1. 초기 상태 ; 초기 상태에 있는 쓰레드 객체는 쓰레드가 생성되어 쓰레드 객체의 start() 메서드가 호출되기 전까지의 기간을 의미한다.

2. 수행 가능한 상태 : start() 메쏘드가 호출되면 스레드는 수행 가능한(Runnable) 상태로 전이된다. 수행 가능한 상태가 쓰레드의 디폴트 상태라고 생각할 수 있다. 만약 쓰레드가 어떠한 상태도 아니라면, 그 쓰레드는 수행가능한 상태이다.

3. 블록킹된 상태 : 한 쓰레드가 특정한 이벤트가 발생하기를 기다리기 때문에 수행을 할 수 없는 상태를 블록킹된 상태라고 정의할 수 있다. 어떤 원격 데이터 서버에게 소켓을 열고 데이터가 들어오기를 기다리는 쓰레드를 이 상태에 있는 쓰레드의 예로 들 수 있다.

4. 종료 상태 : run() 메쏘드 수행이 끝나거나 stop() 메쏘드가 호출되었을 때, 쓰레드는 종료 상태에 들어가게 된다.


  • setPriority() : 가장 우선 순위가 높은 쓰레드가 수행가능한 상태로 되는 그 순간, 자바 가상 머신은 수행되고 있던 쓰레드를 선점하여 가장 우선순위가 높은 쓰레드에게 사용권을 주고 현재 수행권을 갖는 쓰레드가 되도록 한다. “높은 우선순위를 가진 쓰레드는 일반적으로 낮은 우선순위의 쓰레드 보다는 먼저 수행될 가능성이 크다. 그러나 이런 가능성이 가장 우선 순위가 높은 쓰레드가 항상 먼저 실행되어야 한다는 것을 보장하지는 않는다. 쓰레드의 우선순위가 수행순서에 있어서 절대적인 영향력을 행사하지는 않아야 한다.”


  • 쓰레딩 모델

1. 그린 쓰레드 모델 : 가상 머신에 의해 스케줄링 된다. 자바 가상머신의 원래 모델인 그린 쓰레드 모델은 이상적인 형태의 우선순위 기반의 스케줄링을 따른다.

2. 네이티브 쓰레드 모델 : 가상 머신을 호스팅하고 있는 운영체제에 의해 스케줄링 된다.


728x90

'오래된글 > Java' 카테고리의 다른 글

EJB 스팩별 비교표  (0) 2018.04.07
Java Doc 사용법  (0) 2018.04.07
EJB 트렌젝션의 종류  (0) 2018.04.07
EJB CMP의 단점  (0) 2018.04.07
Scrolling Result Sets  (0) 2018.04.07
Comments