Notice
Recent Posts
Recent Comments
Link
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
Archives
Today
Total
관리 메뉴

기록

day 0530 멀티쓰레드_임계영역_쓰레드사이의 통신 본문

📖

day 0530 멀티쓰레드_임계영역_쓰레드사이의 통신

슈슈파나 2024. 5. 30. 17:03

프로세서
: 실행중에 프로그램을 말한다
 
멀티프로세서
: 동시에 여러프로그램이 실행되는 것을 말한다
 
쓰레드
: 프로그램 안에서 실행중인 메소드를 말한다
 
멀티 쓰레드
: 프로그램 안에서 여러개의 메소드가 동시다발로 동작하는 것을 말한다
 
자바에서는 멀티쓰레드 프로그래밍을 위하여
Thread 클래스와 Runnable 인터페이스를 이용할 수 있어요
 
쓰레드가 해야하는 일은
run() 메소드를 오버라이딩해서 그 안에 써주고
 
쓰레드를 동작시키기 위해서는
start() 메소드를 호출합니다
 
- 다음은 참인가요? 거짓인가요?
쓰레드를 가동시키기 위해서 start() 호출해야 하는데 run()을 호출하면 오류가 납니다
=> 거짓) run()을 호출하면 쓰레드를 가동시키는것이 아니고, 일반 메소드처럼 동작한다
 
- 객체를 생성하고 쓰레드를 가동시키는 명령을 쓰시오.

class Hello implements Runnable {
    public void run(){
        어저구.. 저쩌구..
    }
}
Hello h = new Hello();
(new Thread(h)).start();

=> Runnable 인터페이스를 구현한 객체는 직접 start를 호출할 수 없고
     Thread를 통해서 start를 호출해야 합니다
 
java.lang.Thread

 
<< 쓰레드의 우선순위 설정 >>
필요하다면 쓰레드의 우선순위를 설정할 수 있어요
가급적 다른것들보다 더 빨리 작업을 완료해주세요. 라고 요청하는 것이지
요청했다고해서 반드시 더 빨리 작업이 완료된다는것이 보장되지는 않아요
 
setPriority(newPriority);
 
newPriority의 범위
1                                    ~                                      10
Thread.MIN_PRIORITY    Thread.MAX_PRIORITY
 
a = new Person("홍길동");
b = new Person("이순신");
 
b에 최고 우선순위를 설정 해 봅니다
b.setPriority(Thread.MAX_PRIORITY);

package com.kosta.exam02;

class Person extends Thread {
	private String name;
	
	public Person(String name) {
		this.name = name;
	}
	
	@Override
	public void run() {
		for(int i = 1; i <= 5; i++) {
			System.out.println(name + "가 밥을 먹어요 : " + i);
			
			try {
				Thread.sleep(50);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}

public class PersonTest {
	public static void main(String[] args) {
		// 우선순위를 요청하지만 보장할 순 없다
		Person p1 = new Person("가");
		Person p2 = new Person("나");
		Person p3 = new Person("다");
		
		p1.setPriority(1);
		p2.setPriority(1);
		// p3.setPriority(10);
		p3.setPriority(Thread.MAX_PRIORITY);
		
		p1.start();
		p2.start();
		p3.start();
	}
}

join을 안하면 쓰레드가 자동 처리 해줘서 일을 다 끝내기도 전에 다른걸 먼저 동작한다
 
공유자원에 두개이상의 쓰레드가 한번에 접근해서 이런 현상이 있을 수 있어요
한번에 하나의 쓰레드에만 접근을 허용하려면 "임계영역"을 설정해야 합니다
자바에서는 임계영역 설정을 위하여 메소드이름 앞에 synchronized 키워드를 붙여줍니다

package com.kosta.exam04;

// 모금액을 위한 클래스
public class Account {
	private int balance; // 잔액을 위한 변수
	
	public void call(int amount) { // 입금을 위한 메소드
		balance += amount; // 전화 1통에 1000원 입금
	}
	
	public int getBalance() { // 현재 잔액을 반환하는 메소드
		return balance;
	}
}
package com.kosta.exam04;

// 성금자를 위한 클래스(전화를 걸어서 모금액을 증가시키도록 합니다)
// 다른 성금자와 관계없이 계속 입금하기 위하여 쓰레드를 상속받아요
public class Person extends Thread {
	String name; //성금자 이름을 위한 멤버변수
	
	 // 다른 성금자와 모금액을 공유하기 위하여 모금액 클래스인 Account를 멤버변수로 선언합니다
	Account account;

	// 생성시에 이름과 모금액 객체를 매개변수로 전달받아 초기화 해 줍니다
	public Person(String name, Account account) {
		super();
		this.name = name;
		this.account = account;
	}

	// 성금자가 해야 할 일을 run을 오버라이딩하여 써 줍니다
	@Override
	public void run() {
		// 1000원씩 10번 입금하도록 해 봅시다
		for(int i = 1; i <= 10; i++) {
			account.call(1000);
			System.out.println(name + "의 " + i + "번째 입금");
			
			try {
				Thread.sleep(100); // 0.1초 대기
			} catch (InterruptedException e) {
				e.printStackTrace();
			} 
		}
	}
}
package com.kosta.exam04;

public class ARSTest {

	public static void main(String[] args) {
		// 모금액을위한 Account 객체를 생성
		Account account = new Account();
		
		// 성금자의 이름과 모금액을 위한 account 객체를 매개변수로하여
		// 5명의 성금자 객체를 생성한다
		Person p1 = new Person("가", account);
		Person p2 = new Person("나", account);
		Person p3 = new Person("다", account);
		Person p4 = new Person("라", account);
		Person p5 = new Person("마", account);
		
		// 5명의 성금자가 경쟁적으로 입금하기위해 쓰레드를 가동시킨다
		p1.start();
		p2.start();
		p3.start();
		p4.start();
		p5.start();
		
		try {
			p1.join();
			p2.join();
			p3.join();
			p4.join();
			p5.join();
		}catch (Exception e) {
			// TODO: handle exception
		}	
		
		// 전체 모금액을 출력한다
		System.out.println("전체 모금액 : " + account.getBalance());
	}
}

 
<< 임계영역(Critical Section) >>
두개 이상의 쓰레드가 자원을 공유할 때 한번에 하나의 쓰레드에게만 접근을 허용하는 영역을 말하며
자바에서는 그러한 동작을 하는 메소드 이름 앞에 혹은 그러한 기능을 하는 블럭{} 앞에
synchronized 키워드를 붙이면 자동으로 임계영역이되며 한번에 하나의 쓰레드에게만 접근을 허용하게 됩니다

// 임계영역을 위한 synchronized를 추가 해 줍니다
public synchronized void call(int amount) { // 입금을 위한 메소드
    balance += amount; // 전화 1통에 1000원 입금
}
	@Override
	public void run() {
		// 1000원씩 계속 입금하도록 해 봅시다
		for(int i = 1; ; i++) {
			
			// 모금액이 50만원 이상이면 탈출하도록 합니다 
			if(account.getBalance() >= 500000) {
				break;
			}
			
			account.call(1000);
			System.out.println(name + "의 " + i + "번째 입금");
			
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			} 
		}
	}
}

** 문제가 있어요 **
50만원이 넘어요

if(account.getBalance() >= 500000){
	break;
}

** 수정 코드 ** 
Account class(synchronized)에서 50만원이 넘으면 "입금실패!" 되도록 수정한다
synchronized에서 값을 제어한다

// 임계영역 설정을 위하여 synchronized 키워드를 붙여줍니다
public synchronized void call(String name, int n, int amount) { // 입금을 위한 메소드
    System.out.println(name + "의 " + n + "번째 입금");
    if(balance >= 500000) {
        System.out.println("입금실패!");
        return;
    }
    balance += amount; // 전화 1통에 1000원 입금
}

 
** 수정 결과 **

package com.kosta.exam05;

// 모금액을 위한 클래스
public class Account {
	private int balance; // 잔액을 위한 변수
	
	// 임계영역을 위한 synchronized를 추가 해 줍니다
	public synchronized void call(int amount) { // 입금을 위한 메소드
		balance += amount; // 전화 1통에 1000원 입금
	}
	
	public int getBalance() { // 현재 잔액을 반환하는 메소드
		return balance;
	}
}
package com.kosta.exam06;

public class Person extends Thread {
	String name; //성금자 이름을 위한 멤버변수
	Account account; // 모금액

	public Person(String name, Account account) {
		super();
		this.name = name;
		this.account = account;
	}

	@Override
	public void run() {
		// 1000원씩 계속 입금하도록 해 봅시다
		for(int i = 1; ; i++) {
			
			// 모금액이 50만원 이상이면 탈출하도록 합니다 
			if(account.getBalance() >= 500000) {
				break;
			}
			
			account.call(name, i, 1000);
			System.out.println(name + "의 " + i + "번째 입금");
			
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
				e.printStackTrace();
			} 
		}
	}
}
package com.kosta.exam06;

// 모금액을 위한 클래스
public class Account {
	private int balance; // 잔액을 위한 변수
	
	// 임계영역 설정을 위하여 synchronized 키워드를 붙여줍니다
	public synchronized void call(String name, int n, int amount) { // 입금을 위한 메소드
		System.out.println(name + "의 " + n + "번째 입금");
		if(balance >= 500000) {
			System.out.println("입금실패!");
			return;
		}
		balance += amount; // 전화 1통에 1000원 입금
		System.out.println("------------------------------");
	}
	
	public int getBalance() { // 현재 잔액을 반환하는 메소드
		return balance;
	}
}
package com.kosta.exam06;

public class ARSTest {

	public static void main(String[] args) {
		// 모금액을위한 Account 객체를 생성
		Account account = new Account();
		
		// 성금자의 이름과 모금액을 위한 account 객체를 매개변수로하여
		// 5명의 성금자 객체를 생성한다
		Person p1 = new Person("가", account);
		Person p2 = new Person("나", account);
		Person p3 = new Person("다", account);
		Person p4 = new Person("라", account);
		Person p5 = new Person("마", account);
		
		// 5명의 성금자가 경쟁적으로 입금하기위해 쓰레드를 가동시킨다
		p1.start();
		p2.start();
		p3.start();
		p4.start();
		p5.start();
		
		try {
			p1.join();
			p2.join();
			p3.join();
			p4.join();
			p5.join();
		}catch (Exception e) {
			// TODO: handle exception
		}	
		
		// 전체 모금액을 출력한다
		System.out.println("전체 모금액 : " + account.getBalance());
	}
}

 
쓰레드를 가동시키면 가능하면 동시다발로 공평하게 실행이 되게끔 스케줄링을 해 줍니다
만약 두개의 객체가 반드시 1대 1로 동작하도록 하려면 쓰레드 사이의 통신을 이용할 수 있어요
 
<< 쓰레드 사이의 통신 >>
 
두개의 쓰레드가 반드시 1:1로 동작하도록 하려면 쓰레드 사이의 통신이 필요합니다
내가 작업을 하고있는 동안에는 '너는 기다려.' 내가 작업이 끝났으니 '너는 일을 해라.' 와 같이
쓰레드 사이의 통신을 이용하면 1:1로 동작하도록 만들 수 있어요
 
예를들어 "생산자"와 "소비자"가 있다고 할 때 새로운 제품이 생산되어야지만 소비가 일어나고
소비가 일어나야지만 새로운 제품을 생산하는 경우에는
둘 사이에 생산이 되었는지 소비가 있었는지 서로 통신이 필요합니다
생산자는 소비가 일어날 때까지 기다렸다가 소비가 되면 새로운 제품을 생산하고
소비자는 생산이 일어날 때까지 기다렸다가 새로운 제품이 생산되면 소비가 일어나도록
반드시 1:1로 동작하도록 할 수 있어요
 
자바에서는 이러한  쓰레드 사이의 통신을 위하여 자바의 제일 조상클래스인 
Object wait와 notify메소드를 이용합니다
 
내가 상대방의 일이 완료될 때까지 기다리기 위해서는 wait 메소드를 이용하고
내가 일이 끝나서 상대방을 깨울때는 notify 메소드를 이용합니다

 
/생산자와 소비자의 공유자원인 제품만들기/

package com.kosta.exam07;

import java.util.Random;

// 생산자와 소비자가 공유할 자원인 "제품" 클래스를 만들어요
// 새로운 정수를 제품이라 봅시다
public class Product {
	// 제품을 위한 정수형 변수를 선언
	// 생산자는 이 정수를 계속하여 새롭게 만들어주고
	// 소비자는 이 정수를 계속하여 가져다 쓰도록 합니다
	int number; 
	
	// 새 제품이 생산되었는지 판별하기위한 변수
	// 생산자는 새 제품을 생산한 다음 isNew에 true를 저장하고
	// 소비자는 제품을 소비한 후에 isNew에 false를 저장합니다
	boolean isNew;

	// 생산자가 새 제품을 생산하기위한 메소드
	// 생산자가 새 제품을 만들고 있는 동안 소비자는 접근을 못해야하므로 
	// 임계영역 설정을 위하여 synchronized 키워드를 붙입니다
	public synchronized void makeNumber() {
		try {
			// 제품이 소비 될 때가지 기다려요
			while(isNew == true) {
				wait();
			}
			// 새 제품을 만들어요
			Random r = new Random();
			
			// 1 ~ 100까지의 새로운 수
			number = r.nextInt(100) + 1;
			
			// 생산된 제품 출력
			System.out.println("생산자가 생산함 : " + number);
			
			// 새 제품을 만들었다고 표시합니다
			isNew = true;
			
			// 대기중인 소비자를 깨워줍니다
			notify();
			
		}catch (Exception e) {
			// TODO: handle exception
		}
	}
	
	// 소비자가 사용하는 메소드 
	public synchronized int useNumber() {
		int n = 0;
		
		try {
			// 새로운 제품을 생산할 때까지 기다린다 (isNew가 false이 될 때까지)		
			while(isNew == false) {
				wait();
			}
			
			// 제품을 소비합니다
			n = number;
			System.out.println("소비자가 소비함 : " + n);
			// 소비했다는 표시를 합니다
			isNew = false;			
			
			// 대기중인 생산자를 깨워줍니다
			notify();
			
		}catch (Exception e) {
			// TODO: handle exception
		}
		return n;
	}
}
package com.kosta.exam07;

// 생산자 클래스를 만들어요
// 소비자와 상관없이 계속하여 새로운 제품을 생산하기위하여
// thread 클래스를 상속받아 멀티쓰레드가 가능하도록 합니다
public class Producer extends Thread {

	// 제품을 멤버변수로 선언
	private Product product;

	// 생성시에 제품을 매개변수로 전달받아 초기화  합니다
	//이 제품이 소비자와 공유하는 자원입니다
	public Producer(Product product) {
		super();
		this.product = product;
	}
	
	// 생산자 쓰레드가 해야 할 일을 run을 오버라이딩하여 써 줍니다
	@Override
	public void run() {
		// 10개의 새로운 제품을 생산하도록 합니다
		for(int i = 1; i <= 10; i++) {
			try {
				product.makeNumber();
				Thread.sleep(100);
			}catch (Exception e) {
				// TODO: handle exception
			}
		}
	}
}
package com.kosta.exam07;

// 소비자 클래스를 만들어요
// 생산자와 관계없이 계속하여 제품을 소개하도록하기 위하여 멀티쓰레드가 되게 합니다
public class Consumer extends Thread {
	
	// 생산자와 제품을 공유하기 위하여 멤버변수로 제품을 선언합니다
	private Product product;
	
	// 생성시에 제품을 매개변수로 전달받아 초기화 합니다
	public Consumer(Product product) {
		this.product = product;
	}
	
	// run을 오버라이딩 하여 소비자가 해야 할 일을 써줍니다
	@Override
	public void run() {
		for(int i = 1; i <= 10; i++) {
			product.useNumber();
			
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}
package com.kosta.exam07;

public class MainTest {
	public static void main(String[] args) {
		// 생산자 객체와 쓰레드 객체를 생성하여 가동시키세요
		Product product = new Product();
		Producer producer = new Producer(product);
		Consumer consumer = new Consumer(product);
		
		producer.start();
		consumer.start();
	}
}

 


 
14:00 ~
 

그림판 ㅈㅐㅁㅣㄸㅏ ㅎㅎ...
 
<< GUI >> 
 
CUI : Character User Interface
=> 사용자와 컴퓨터가 문자로 의사소통하는 환경을 말한다
 
GUI : Graphic User Interface
=> 사용자와 컴퓨터가 그래픽요소로 의사소통 하는것을 말한다
 
자바는 GUI를 위한 ( awt ) 패키지와 ( swing ) 패키지를 만들어 두었습니다
 
<< 화면 구성 요소 >> 
JFrame  :  창
Jbutton  :  버튼
JTextFeiled  :  한줄 글자 입력
JTextArea  :  여러줄 글자 입력
JLabel  :  입력할 것 표시
...

 
/JFrame 상속받기/

public MyFrame() {
    button01 = new JButton("남자");	
    button02 = new JButton("여자");

    add(button01);
    add(button02);
}

 
배치관리자(LayoutManager)
: 화면 구성요소들을 배치하는 관리자

 
- FlowLayout
: 화면 구성요소들을 왼쪽에서 오른쪽으로, 위에서 아래쪽으로 물 흐르듯 배치하는 관리자 입니다
 
- GridLayout
: 화면을 행,열로 분할하여 배치하는 관리자 입니다 
 
- BorderLayout
: 화면을 동, 서, 남, 북, 가운데 5개의 영역으로 분할하여 배치하는 관리자 입니다
  보통 5개의 영역에 모두 배치하기보다는 가운데를 중심으로하여 중요한 컨텐츠를 가운데에 놓고
  부가적인 메뉴등을 위, 아래, 왼쪽, 오른쪽 배치하여 사용합니다
 
  즉 위, 아래, 왼쪽, 오른쪽은 생략하여 사용하고 가운데는 생략하지 않는것이 일반적입니다

// 배치관리자를 Flowlayout으로 설정
setLayout(new FlowLayout());

FlowLayout으로 버튼 15개 만들기 button1, button2, button3...
 

package com.kosta.exam09;

import java.awt.Button;
import java.awt.FlowLayout;
import java.awt.HeadlessException;

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

public class MyButton extends JFrame {
	JButton button;

	public MyButton() {
		for(int i = 0; i <= 15; i++) {
		button = new JButton("Button" + i);
		add(button);
		}
		setLayout(new FlowLayout());

		setSize(400,300);
		setVisible(true);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}
	
	public static void main(String[] args) {
		new MyButton();
	}
}

 
/배열로 출력하기/

package com.kosta.exam09;

import java.awt.FlowLayout;

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

public class FlowLayoutTest extends JFrame{

	JButton[] arr = new JButton[15];
	
	public FlowLayoutTest (){
		
		setLayout(new FlowLayout());
		
		for(int i = 0; i < arr.length; i++) {
			arr[i] = new JButton("버튼" + i);
			add(arr[i]);
		}
		
		setSize(400,300);
		setVisible(true);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}
	public static void main(String[] args) {
		new FlowLayoutTest();
	}
}

 

public class GridLayoutTest extends JFrame{

	JButton button;
	
	public GridLayoutTest (){
			// 3행 5열
			// setLayout(new GridLayout(3, 5));
			// 5행 3열
			setLayout(new GridLayout(5, 3));
            
			for(int i = 0; i <= 15; i++) {
			button = new JButton("Button" + i);
			add(button);
			}

			setSize(400,300);
			setVisible(true);
			setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		}
public class GridLayoutTest02 extends JFrame{

	JButton[] arr = new JButton[15];
	
	// 설정한 그리드의 수와 컴포넌트의 수가 맞지 않고
	// 컴포넌트에 수를 행렬에 맞출 수 있으면 알아서 맞추어 준다
	public GridLayoutTest02 (){
		
		setLayout(new GridLayout(3, 5));
		
		for(int i = 1; i <=15; i++) {
			add(new JButton("button" + i));
		}
		
		setSize(400,300);
		setVisible(true);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}
	public static void main(String[] args) {
		new GridLayoutTest02();
	}
}

 

public class BorderLayoutTest extends JFrame {

	public BorderLayoutTest() {
		setLayout(new BorderLayout());
		add(new JButton("위"), BorderLayout.NORTH);
		add(new JButton("아래"), BorderLayout.SOUTH);
		add(new JButton("왼쪽"), BorderLayout.WEST);
		add(new JButton("오른쪽"), BorderLayout.EAST);
		add(new JButton("가운데"), BorderLayout.CENTER);
		
		setSize(400,300);
		setVisible(true);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}
	public static void main(String[] args) {
		new BorderLayoutTest();
	}
}

 
/PROGRAMMING 2/

JLabel, JText, 서브컨테이너 2개 panel 1.grid : 3행2열 2.flow : 버튼2개

package com.kosta.exam10;

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class AddTest extends JFrame implements ActionListener {

	JTextField jtf01;
	JTextField jtf02;
	JTextField jtf03;
	
	public AddTest() {
		jtf01 = new JTextField(10);
		jtf02 = new JTextField(10);
		jtf03 = new JTextField(10);
		
		JPanel p_center = new JPanel(); // gridLayout
		JPanel p_south = new JPanel(); // flowLayout
		
		p_center.setLayout(new GridLayout(3, 2));
		p_south.setLayout(new FlowLayout(FlowLayout.CENTER)); // 가운데 정렬
		
		p_center.add(new JLabel("첫번째 정수 : "));
		p_center.add(jtf01);
		p_center.add(new JLabel("두번째 정수 : "));
		p_center.add(jtf02);
		p_center.add(new JLabel("세번째 정수 : "));
		p_center.add(jtf03);
		
		JButton btnAdd = new JButton("Add");
		JButton btnClear = new JButton("Clear");
		
		p_south.add(btnAdd);
		p_south.add(btnClear);
		
		setLayout(new BorderLayout());
		add(p_center, BorderLayout.CENTER);
		add(p_south, BorderLayout.SOUTH);
		
		setSize(400,150);
		setVisible(true);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);	
		
		// 이벤트 처리 담당자가 this
		btnAdd.addActionListener(this);
		btnClear.addActionListener(this);
	}
	
	@Override
	public void actionPerformed(ActionEvent e) {
		System.out.println("버튼이 눌러짐");
		
		// 눌러진 버튼의 글자를 갖고온다
		String cmd = e.getActionCommand();
		
		System.out.println(cmd);
	}
	
	public static void main(String[] args) {
		new AddTest();
	}
}

 
/더하기 기능 추가하기/

package com.kosta.exam10;

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class AddTest extends JFrame implements ActionListener {

	JTextField jtf01;
	JTextField jtf02;
	JTextField jtf03;
	
	public AddTest() {
		jtf01 = new JTextField(10);
		jtf02 = new JTextField(10);
		jtf03 = new JTextField(10);
		
		JPanel p_center = new JPanel(); // gridLayout
		JPanel p_south = new JPanel(); // flowLayout
		
		p_center.setLayout(new GridLayout(3, 2));
		p_south.setLayout(new FlowLayout(FlowLayout.CENTER)); // 가운데 정렬
		
		p_center.add(new JLabel("첫번째 정수 : "));
		p_center.add(jtf01);
		p_center.add(new JLabel("두번째 정수 : "));
		p_center.add(jtf02);
		p_center.add(new JLabel("연산 결과 : "));
		p_center.add(jtf03);
		
		JButton btnAdd = new JButton("Add");
		JButton btnClear = new JButton("Clear");
		
		p_south.add(btnAdd);
		p_south.add(btnClear);
		
		setLayout(new BorderLayout());
		add(p_center, BorderLayout.CENTER);
		add(p_south, BorderLayout.SOUTH);
		
		setSize(400,150);
		setVisible(true);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);	
		
		// 이벤트 처리 담당자가 this
		btnAdd.addActionListener(this);
		btnClear.addActionListener(this);
	}
	
	@Override
	public void actionPerformed(ActionEvent e) {
		System.out.println("버튼이 눌러짐");
		
		// 눌러진 버튼의 글자를 갖고온다
		String cmd = e.getActionCommand();
		
		System.out.println(cmd);
		
		if(cmd.equals("Add")) {			
			int num1 = Integer.parseInt(jtf01.getText());
			int num2 = Integer.parseInt(jtf02.getText());
			
			int result = num1 + num2;
			
			// String으로 변환하기 +""
			jtf03.setText(result+"");
		}else if(cmd.equals("Clear")) {
			// Clear하면 지워주기
			jtf01.setText("");
			jtf02.setText("");
			jtf03.setText("");
		}
	}
	
	public static void main(String[] args) {
		new AddTest();
	}
}
}else if(cmd.equals("Clear")) {
    // Clear하면 지워주기
    jtf01.setText("");
    jtf02.setText("");
    jtf03.setText("");
}

 
/ActionListener 이름없는 객체 생성하기/

// 이벤트 처리 담당자
btnAdd.addActionListener(new ActionListener() {

    // 이름없는 객체 만들기
    @Override
    public void actionPerformed(ActionEvent e) {
        int a = Integer.parseInt(jtf01.getText());
        int b = Integer.parseInt(jtf02.getText());

        int r = a + b;
        jtf03.setText(r + "");
    }
});

btnClear.addActionListener(new ActionListener() {

    @Override
    public void actionPerformed(ActionEvent e) {
        jtf01.setText("");
        jtf02.setText("");
        jtf03.setText("");
    }
});

 

 
** 전체 코드 **

package com.kosta.exam10;

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class AddTest02 extends JFrame  {

	JTextField jtf01;
	JTextField jtf02;
	JTextField jtf03;
	
	public AddTest02() {
		jtf01 = new JTextField(10);
		jtf02 = new JTextField(10);
		jtf03 = new JTextField(10);
		
		JPanel p_center = new JPanel(); // gridLayout
		JPanel p_south = new JPanel(); // flowLayout
		
		p_center.setLayout(new GridLayout(3, 2));
		p_south.setLayout(new FlowLayout(FlowLayout.CENTER)); // 가운데 정렬
		
		p_center.add(new JLabel("첫번째 정수 : "));
		p_center.add(jtf01);
		p_center.add(new JLabel("두번째 정수 : "));
		p_center.add(jtf02);
		p_center.add(new JLabel("연산 결과 : "));
		p_center.add(jtf03);
		
		JButton btnAdd = new JButton("Add");
		JButton btnClear = new JButton("Clear");
		
		p_south.add(btnAdd);
		p_south.add(btnClear);
		
		setLayout(new BorderLayout());
		add(p_center, BorderLayout.CENTER);
		add(p_south, BorderLayout.SOUTH);
		
		setSize(400,150);
		setVisible(true);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);	
		
		// 이벤트 처리 담당자
		btnAdd.addActionListener(new ActionListener() {
			
			// 이름없는 객체 만들기
			@Override
			public void actionPerformed(ActionEvent e) {
				// String cmd = e.getActionCommand();
				// System.out.println(cmd);
				
				int a = Integer.parseInt(jtf01.getText());
				int b = Integer.parseInt(jtf02.getText());
				
				int r = a + b;
				jtf03.setText(r + "");
			}
		});
		
		btnClear.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				jtf01.setText("");
				jtf02.setText("");
				jtf03.setText("");
			}
		});
	}
	
	public static void main(String[] args) {
		new AddTest02();
	}
}

 
- 오늘 학습내용 (임계영역, 쓰레드 사이의 통신, 레이아웃매니저, 버튼 이벤트 처리, 서브 컨테이너를 이용한 배치)에
  대하여 요약 및 정리하도록 합니다
- pdf "GUI 이벤트 처리"의 1, 3, 4, 5, 6번 중에 선택하여 프로그래밍 해 봅니다
 

package com.kosta.exam10;

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class Test03 extends JFrame {
	JTextField t1;
	JTextField t2;
	JTextField t3;
	
	public Test03() {
		t1 = new JTextField(10);
		t2 = new JTextField(10);
		t3 = new JTextField(10);
		
		JPanel p_center = new JPanel();
		JPanel p_south = new JPanel();
		
		p_center.setLayout(new GridLayout(2, 2));
		p_south.setLayout(new FlowLayout());
		
		p_center.add(new JLabel("나의 BMI 지수는 얼마나 될까?"));
		p_center.add(t1);
		p_center.add(new JLabel("나의 체중(kg) : "));
		p_center.add(t2);
		p_center.add(new JLabel("나의 키(cm) : "));
		p_center.add(t3);
		
		JButton btn = new JButton("BMI 확인하기"); 
		
		p_south.add(btn);
		
		setLayout(new BorderLayout());
      // t1 : north에 넣기
		add(p_center, BorderLayout.CENTER);
		add(p_south, BorderLayout.SOUTH);
		
		setSize(400,150);
		setVisible(true);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);	
		
		btn.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				// TODO Auto-generated method stub
				
			}
		});
	}
	
	public static void main(String[] args) {
		new Test03();
	}
}

 

'📖' 카테고리의 다른 글

day 0603 메모장  (0) 2024.06.03
day 0531 GUI 연습  (0) 2024.05.31
day 0529 멀티쓰레드  (1) 2024.05.29
day 0528 StringAndStringBuffer_예외처리  (1) 2024.05.28
day 0527 문자열  (0) 2024.05.27