Java start()

2023. 2. 11. 21:45Java

프로젝트 내 src 내 javabasic 패키지 내 Ex3ThreadCircle.java

package javabasic;

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;

public class Ex3ThreadCircle extends JFrame implements ActionListener {
	JButton btnStart, btnStop;
	boolean bStart = false;// true면 원그리기 반복
	// 내부 클래스 선언
	CircleDraw draw = new CircleDraw();

	public Ex3ThreadCircle(String title) {
		// TODO Auto-generated constructor stub
		super(title);
		this.setBounds(700, 100, 500, 500);// 시작위치x,y,크기 w,h
		// super로 해도 되고 this로 해도 됨 super는 조상
		// this로 해도 상속을 받아서 괜찮음
		// this.getContentPane().setBackground(Color.orange);//프레임위에 있는 패널의 색상 변경
		this.getContentPane().setBackground(Color.white);// 프레임위에 있는 패널의 색상 변경
		this.setDesign();// 디자인 코드
		this.setVisible(true);// 보이게 하기
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);// 프로그램을 종료해주는 메서드
	}

	public void setDesign() {
		this.setLayout(null);

		btnStart = new JButton("Start");
		btnStart.setBounds(100, 20, 100, 30);
		btnStart.addActionListener(this);

		btnStop = new JButton("Stop");
		btnStop.setBounds(300, 20, 100, 30);
		btnStop.addActionListener(this);

		this.add(btnStart);
		this.add(btnStop);

		draw.setBounds(0, 60, 500, 400);
		draw.setBackground(Color.BLACK);
		this.add(draw);
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		// TODO Auto-generated method stub
		Object ob = e.getSource();

		Thread th = new Thread(draw);
		if (ob == btnStart) {
			bStart = true;
		} else if (ob == btnStop) {
			bStart = false;
		}
		th.start();// 내부클래스의 run메소드 호출
	}

	// 원그리는 내부클래스
	class CircleDraw extends Canvas implements Runnable {
		int x, y;
		int red, green, blue;

		@Override
		public void run() {
			// TODO Auto-generated method stub
			while (bStart) {
				x = (int) (Math.random() * 500);
				y = (int) (Math.random() * 400) + 50;
				red = (int) (Math.random() * 256);
				green = (int) (Math.random() * 256);
				blue = (int) (Math.random() * 256);

				// 0~9까지
				// System.out.println((int)(Math.random()*10));
				// System.out.println((int)(Math.random()*10));
				// System.out.println((int)(Math.random()*10));
				// System.out.println((int)(Math.random()*10));
				// System.out.println((int)(Math.random()*10));
				// System.out.println((int)(Math.random()*10));
				// this.repaint();//paint 메서드 호출,이전 원이 지워진다 쓰지 말고 paint 쓸것
				this.paint(getGraphics());

				try {
					Thread.sleep(100);// 0.1초
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			
			while (!bStart) {
				System.out.println("Stop 버튼을 눌렀고 Thread th 객체 흐름은 여전히 흘러가는 중입니다.");
				
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}

		@Override
		public void paint(Graphics g) {
			// TODO Auto-generated method stub
			// super.paint(g);//지워지면서 다시 그려지지 않도록 없애준다
			System.out.println("CircleDraw 내부클래스 paint 호출");
			if (bStart) {
				g.setColor(new Color(red, green, blue));
				g.fillOval(x, y, 60, 60);
			}
		}
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Ex3ThreadCircle ex = new Ex3ThreadCircle("스레드연습");
	}

}

위의 코드를 본다.

actionPerformed(ActionEvent e) 메서드는

btnStart 버튼과 btnStop 버튼에 대한 액션이 발생할 때 마다, 즉 버튼이 눌릴 때 마다 호출되는 메서드인데

actionPerformed(ActionEvent e) 메서드가 호출 될 때 마다

새롭게 Thread 객체가 생성된다. 새로운 Thread 객체가 생성이 되는 것이지만 Thread th = new Thread(draw);

라고 작성하여서 새로운 Thread 를 생성하였다기 보다는 계속해서 같은 Thread 클래스의 객체 변수 th 를 생성하는 것이라서 th 변수를 생성했다가 재생성하니 결국에는 th 변수를 생성했다가 없앴다가 생성했다가 제거했다가 하는 식으로 도돌이표를 그리는 것이다. 생성했다가 파괴했다가 생성했다가 없애니 Thread 클래스의 th 객체변수를 갱신하는 것이다.

그리고 나서 Thread 객체 th 변수에 start() 메서드를 쓰면 run() 메서드를 호출한다. 결론적으로는 main(String[] args) 메서드를 돌리는 현재 thread 와 Thread th = new Thread(draw); ... th.start(); 두 줄이 호출하는 Runnable 인터페이스를 구현한 내부클래스의 run() 메서드가 돌면서 드러난 두번째 thread 가 함께 공존하게 된다. 그리고 두번째 thread 는 버튼을 누를 때 마다 새로 생성되고 이전의 두번째 thread 는 없어지고 또 버튼을 누르면 생성되고 없어지는 것이라서 최종적으로는 프로그램 내에 두 개의 thread 만이 동시에 작동한다.


void java.lang.Thread.sleep(long millis) throws InterruptedException

public static native void sleep(long millis) throws InterruptedException;

sleep(long millis) 메서드는 static 메서드라서 Thread 클래스로부터 객체를 생성하지 않고도 바로 사용할 수 있다.

 

Thread.sleep(long millis) 메서드는

시스템 특별 시계(timers) 와 schedulers 으 정밀도와 정확도에 따라서,

밀리초(천분의1초) 단위로 지정된 수의 시간 동안

현재 실행하는 중인 thread 를 잠들게 한다, 즉 잠시동안 실행을 중지한다.

여기서 현재 실행하는 중인 thread 는 위의 코드에서 봤을 때 두 가지 thread 중에 무엇이냐 하면 Runnable 인터페이스(규격) 를 구현한 클래스 내부에 run() 메서드 안에 Thread.sleep(long millis) 메서드를 이용했으므로

Thread th = new Thread(draw); ... th.start(); 두 줄로 run() 메서드가 실행된 Thread th 임을 알 수 있다.

 

Thread.sleep(long millis) 메서드는 run() 메서드 내부에서 쓰면 

run() 메서드 내부에 쓴 아무 작업하는 코드 속도를 현저히 줄게 해서

위의 코드에서는 너무 빠르게 그리지 않게 해 주거나 콘솔에 출력하는 속도를 느리게 해줘서 비교적 알아보기 쉽게 만들어 준다.


 

'Java' 카테고리의 다른 글

Java UnknownHostException  (0) 2023.02.11
Java InetAddress  (0) 2023.02.11
Java Thread class 와 Runnable interface  (0) 2023.02.11
Java run()  (0) 2023.02.11
Java KeyEvent  (0) 2023.02.11