mojo's Blog

wait(), notify(), notifyAll() 을 이용하여 스레드를 동기화하기 본문

Java

wait(), notify(), notifyAll() 을 이용하여 스레드를 동기화하기

_mojo_ 2021. 8. 9. 00:37

wait(), notify(), notifyAll()를 이용하면 producer-consumer 문제의 스레드 동기화를 해결할 수 있다.

java.lang.Object 클래스는 스레드 사이에 동기화를 위한 3개의 메소드 wait(), notify(), notifyAll() 를 제공한다.

모든 객체는 Object 클래스를 상속받기 때문에, 자바는 모든 객체가 동기화 객체가 될 수 있도록 설계하였다.

 

wait() : 다른 스레드가 이 객체의 notify()를 불러줄 때까지 대기한다.

 

notify() : 이 객체에 대기 중인 스레드를 깨워 RUNNABLE 상태로 만든다. 2개 이상의 스레드가 대기 중이라도 오직 한 개의 스레드만 깨워 RUNNABLE 상태로 한다.

 

notifyAll() : 이 객체에 대기 중인 모든 스레드를 깨우고 모두 RUNNABLE 상태로 만든다.

 


wait(), notify() 를 이용해서 바를 채우는 code

 

import javax.swing.*; // JFrame
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.*; // Container
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.MouseMotionListener;
import java.util.Vector;
import java.awt.*;

public class TabAndThreadEx extends JFrame{
	private MyLabel bar = new MyLabel(100);
	
	class MyLabel extends JLabel{
		private int barSize = 0;
		private int maxBarSize;
		
		MyLabel(int maxBarSize){
			this.maxBarSize=maxBarSize;
		}
		
		public void paintComponent(Graphics g) {
			super.paintComponent(g);
			g.setColor(Color.MAGENTA);
			int width = (int)(((double)(this.getWidth()))/maxBarSize*barSize);
			if(width==0) return;
			g.fillRect(0, 0, width, getHeight());
		}
		
		synchronized public void fill() {
			if(barSize==maxBarSize) {
				try {
					wait();
				} catch(InterruptedException e) { return; }
				
			}
			barSize++;
			repaint();
			notify(); // ConsumerThread 스레드 깨우기
		}
		
		synchronized public void consume() {
			if(barSize==0) {
				try {
					wait();
				} catch(InterruptedException e) { return; }
			}
			barSize--;
			repaint();
			notify();
		}
	}
	
	class ConsumerThread extends Thread{
		private MyLabel bar;
		public ConsumerThread(MyLabel bar) {
			this.bar = bar;
		}
		
		public void run() {
			while(true) {
				try {
					sleep(200);
					bar.consume();
				} catch(InterruptedException e) { return; }
			}
		}
	}
	
	TabAndThreadEx(String title){
		super(title);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		Container c = getContentPane();
		c.setLayout(null);
		
		bar.setBackground(Color.ORANGE);
		bar.setOpaque(true);
		bar.setLocation(20,50);
		bar.setSize(300,20);
		c.add(bar);
		
		c.addKeyListener(new KeyAdapter() {
			public void keyPressed(KeyEvent e) {
				bar.fill();
			}
		});
		setSize(350, 200);
		setVisible(true);
		
		c.setFocusable(true);
		c.requestFocus();
		ConsumerThread th = new ConsumerThread(bar);
		th.start();
	}
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		new TabAndThreadEx("아무거나 빨리 눌러 바 채우기");
	}

}

 

Comments