- 벡터로 자료를 영구 보관시키고있슴

 - 마우스를 드래그한 범위를 선을 그림

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class LineDrawEx extends JFrame {
	
	public LineDrawEx(){
		setContentPane(new MyPanel());
		setSize(300,300);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setVisible(true);
	}
	
	class MyPanel extends JPanel{
		Point startP = null;
		Point endP = null;
		
		public MyPanel(){
			this.addMouseListener(new MyMouseListener());
		}
		
		class MyMouseListener extends MouseAdapter{
			public void mousePressed(MouseEvent e){
				startP = e.getPoint(); // 클릭한부분을 시작점으로
			}
			public void mouseReleased(MouseEvent e){
				endP = e.getPoint(); // 드래그 한부분을 종료점으로
				Graphics g = getGraphics();
				g.drawLine(startP.x, startP.y, endP.x, endP.y);
			}
		}
	}
	
	public static void main(String[] args) {
		new LineDrawEx();
	}
}

이렇게 하게되면 드래그를 통해서 선은 그려지나..... 영구 보존되진않는다. 화면에 변화생기면 지워진다.
 


벡터를 이용해서 영구적 자료 보관하면서 그리기
 
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Vector;

public class LineDrawEx extends JFrame {
	
	public LineDrawEx(){
		setContentPane(new MyPanel());
		setSize(300,300);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setVisible(true);
	}
	
	class MyPanel extends JPanel{
		Vector<Point> sv = new Vector<Point>(); // 시작
		Vector<Point> se = new Vector<Point>(); // 끝점
		
		public MyPanel(){
			this.addMouseListener(new MyMouseListener()); // 리스너
		}
		
		public void paintComponent(Graphics g){
			super.paintComponent(g); // 부모 페인트호출
			
			if(sv.size() == 0) // 벡터에 암것도없으면 리턴
				return;
			
			for(int i=0;i<sv.size();i++){ //벡터크기만큼
				Point sp = sv.get(i); // 벡터값을꺼내다
				Point ep = se.get(i);	
				g.drawLine(sp.x, sp.y, ep.x, ep.y);//그리다
			}
		}
		
		class MyMouseListener extends MouseAdapter{
			public void mousePressed(MouseEvent e){
				sv.add(e.getPoint()); // 클릭한부분을 시작점으로
			}
			public void mouseReleased(MouseEvent e){
				se.add(e.getPoint()); // 드래그 한부분을 종료점으로
				repaint(); // 다시그려라
			}
		}
	}
	
	public static void main(String[] args) {
		new LineDrawEx();
	}
}


기존 기능에서  마우스를찍고 드래그하는 위치를 보여주는 예쩨

 

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Vector;

public class LineDrawEx extends JFrame {
	
	public LineDrawEx(){
		setContentPane(new MyPanel());
		setSize(300,300);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setVisible(true);
	}
	
	class MyPanel extends JPanel{
		
		Point startP=null;
		Point endP=null;
		
		Vector<Point> sv = new Vector<Point>(); // 시작
		Vector<Point> se = new Vector<Point>(); // 끝점

		public MyPanel(){
			//리스너를 공통으로해야  변수들이 공유된다.
			MyMouseListener ml = new MyMouseListener();
			
			this.addMouseListener(ml); // 리스너
			this.addMouseMotionListener(ml);
		}
		
		public void paintComponent(Graphics g){
			super.paintComponent(g); // 부모 페인트호출
			
			if(sv.size() != 0){
				for(int i=0;i<se.size();i++){ //벡터크기만큼
					Point sp = sv.get(i); // 벡터값을꺼내다
					Point ep = se.get(i);	
					g.drawLine(sp.x, sp.y, ep.x, ep.y);//그리다
				}
			}
			if(startP != null)
				g.drawLine(startP.x, startP.y, endP.x, endP.y);				
		}
		
		class MyMouseListener extends MouseAdapter implements MouseMotionListener{
			public void mousePressed(MouseEvent e){
				startP = e.getPoint();
				sv.add(e.getPoint()); // 클릭한부분을 시작점으로
			}
			public void mouseReleased(MouseEvent e){
				se.add(e.getPoint()); // 드래그 한부분을 종료점으로
				endP = e.getPoint();
				repaint(); // 다시그려라
			}
			
			public void mouseDragged(MouseEvent e){
				endP = e.getPoint();
				repaint();
			}
			
			public void mouseMoved(MouseEvent e){
				
			}
		}
	}
	
	public static void main(String[] args) {
		new LineDrawEx();
	}
}

 

블로그 이미지

맨오브파워

한계를 뛰어 넘어서..........

,

- 4개의 값을 입력받고, 그것을 그래프로 나타내준다.

 

 

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
 
public class GraphicsObjectEx extends JFrame {
	Container contentPane; // 컨테이너 생성
	int[] data = {0,0,0,0}; // 차트의 값 저장배열
	int[] arcAngle = new int[4]; 
 
	Color[] color = {Color.RED, Color.BLUE, // 색상 
			  Color.MAGENTA, Color.ORANGE};
 
	String[] itemName = {"티아라", "소녀시대", // 비교대상 
			                  "FX", "카라"};
 
	JTextField[] tf  = new JTextField[4]; // 텍스트필드
	ChartPanel chartPanel = new ChartPanel(); // 차트패널
 
	public GraphicsObjectEx(){ // 생성자
		setTitle("아이돌 인기도");
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		contentPane = getContentPane(); // 컨테이너 갯
		contentPane.add(new InputPanel(), BorderLayout.NORTH);
		contentPane.add(chartPanel, BorderLayout.CENTER);
		setSize(500,350);
		setVisible(true);
		drawChart(); // 차트 메소드 호출
	}
 
	void drawChart(){ // 차트를 그린다
		int sum=0; // 초기값 0
		for(int i=0;i<data.length;i++){ // 데이터 값만큼 루프
			data[i] = Integer.parseInt(tf[i].getText());
			sum+=data[i];
		}
		if(sum == 0) 
			return;
 
		for(int i=0;i<data.length;i++){ 
			arcAngle[i] = (int)Math.round((double)data[i]/(double)sum*360);
			chartPanel.repaint(); // 차트패널의 PAINT호출
		}
	}
 
	class InputPanel extends JPanel{ // 입력패널
		public InputPanel(){
			this.setBackground(Color.LIGHT_GRAY); //배경
 
			for(int i=0;i<tf.length;i++){ // 현 가진갯수만큼
				tf[i] = new JTextField("0", 5);
				tf[i].addActionListener(new MyActionListener()); //리스너
				add(new JLabel(itemName[i]));
				add(tf[i]);
			}
		}
	}
 
	class MyActionListener implements ActionListener{ //액션리스너
		public void actionPerformed(ActionEvent e){ //텍스트필드변화시
			JTextField t = (JTextField)e.getSource();
			int n;
 
			try{
				n = Integer.parseInt(t.getText());
			}
			catch(NumberFormatException ex){
				t.setText("0");
				return;
			}
			drawChart(); // 호출	
		}
	}
 
	class ChartPanel extends JPanel{ // 차트 표시 패널
 
		public void paintComponent(Graphics g){
 
			super.paintComponent(g);//부모 패인트호출
 
			int startAngle = 0;
 
			for(int i=0;i<data.length;i++){
				g.setColor(color[i]);
				g.drawString(itemName[i]+""+Math.round
			   (arcAngle[i]*100/360)+"%", 50+i*100,20);
			}
 
			for(int i=0;i<data.length;i++){
				g.setColor(color[i]);
				g.fillArc(150,50,200,200,startAngle,arcAngle[i]);
				startAngle = startAngle + arcAngle[i];
			}
		}
	}
 
	public static void main(String[] args) {
		new GraphicsObjectEx();
	}
}
블로그 이미지

맨오브파워

한계를 뛰어 넘어서..........

,

각 숫자는 3개이고 재각각 스레드에서 동작한다

 

 

import javax.swing.*;
import java.awt.*;

public class TimerThreadFrame extends JFrame{
	public TimerThreadFrame(){
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setLayout(new FlowLayout());
		
		JLabel la = new JLabel("0");
		la.setFont(new Font("Helvetica", Font.BOLD, 80));
		la.setHorizontalAlignment(JLabel.CENTER);
		add(la);
		
		JLabel la2 = new JLabel("50");
		la2.setFont(new Font("Helvetica", Font.BOLD, 80));
		la2.setHorizontalAlignment(JLabel.CENTER);
		add(la2);	
		
		JLabel la3 = new JLabel("100");
		la3.setFont(new Font("Helvetica", Font.BOLD, 80));
		la3.setHorizontalAlignment(JLabel.CENTER);
		add(la3);	
		
		setSize(500, 150);
		setVisible(true);
		
		TimerThread tid = new TimerThread(la,10);
		tid.start();
		
		TimerThread tid2 = new TimerThread(la2,100);
		tid2.start();
		
		Thread th3 = new Thread(new ThreadRunable(la3, 1000));
		th3.start();
		
	}
	
	public static void main(String[] args) {
		new TimerThreadFrame();
	}
}

class TimerThread extends Thread{
	JLabel a;
	int n,m;
	
	public TimerThread(JLabel a, int m){
		this.a = a;
		this.m = m;
		n = Integer.parseInt(a.getText());
	}
	
	public void run(){
		while(true){
			try{
				sleep(m);
			}catch(InterruptedException e){
				return;
			}
			n++;

			a.setText(Integer.toString(n));
		}
	}
}

class ThreadRunable implements Runnable{
	JLabel a;
	int n,m;
	
	public ThreadRunable(JLabel a, int m){
		this.a = a;
		this.m = m;
	}
	public void run(){
		while(true){
			try{
				Thread.sleep(m);
			}catch(InterruptedException e){
				return;
			}
			n++;

			a.setText(Integer.toString(n));
		}
	}
}
블로그 이미지

맨오브파워

한계를 뛰어 넘어서..........

,

Synchronized 키워드

- 한스레드만이 독점적으로 실행되어야 하는 부분(동기화 코드의) 표시하는 키워드

- 임계영역

- 메소드 전체 블럭

- 일부분 코드 블럭

 

모니터란? 객체를 독점적으로 사용할수 있는 권한

               모니터를 먼저 소유한 스레드가 몬티너 내놀때까지 다른스레드는 기다린다

 

동기화 객체

두개이상의 스레드 사이에 동기화 작업에 사용되는객체

 

동기화 메소드

- synchonized블럭 내에서만 사용해야됨

 

wait()

- Object 클래스가 가진 메소드이다.

- 다른 스레드가 notify() 불러줄떄까지 기다린다.

 

notify()

- wait()로 인해 대기중인 스레드 깨우고 RUNABLE을 만든다.

- 2개이상의 스레드가 대기중이라도 오직 한개의 스레드만 꺠워 RUNABLE한다.

 

notifyAll()

- wait()를 호출로 인해 대기중인 모든스레드를 깨워버린다.

 


 

스레드 동기화는 크리티컬 섹션 임계영역을 서로 상호 배제 해주는 것이다.

 

C와 약간 스타일은 다르지만... 유형은 비슷하다 볼수있다.

 


- 크리티컬 섹션 임계영역의 변수 SUM이 존재한다.

- 2개의 스레드가 1개의 변수를 공유하는것이다..

- Synchorinzed를 사용하지 않는다면 임계영역 상호배제가 이루어지지않는다.

 

동기화를 사용한 소스코드

public class SynchronizedEx {
	
	public static void main(String[] args) {
		
		// 동기화 객체 선언
		SyncObject obj = new SyncObject();
		
		//스레드 객체 선언
		Thread th1 = new WorkerThread("지연", obj); 
		Thread th2 = new WorkerThread("은정", obj);
		
		th1.start(); // 스레드 시작
		th2.start();
	}
}

class SyncObject{ // 동기화 클래스
	
	int sum=0; // 공유영역
	
	synchronized void add(){
		
		int n = sum; 
		Thread.currentThread().yield(); // 현재스레드 양보해라 값을더하는동안
		n+=10;
		sum = n; // sum을 덮어라 자기값으로	
		System.out.println(Thread.currentThread().getName() + " : " + sum);
	}
	
	int getSum(){
		return sum;
	}
}

class WorkerThread extends Thread{
	
	SyncObject sObj; // 동기화 객체 선언
	
	//생성자
	WorkerThread(String name, SyncObject sObj){
		super(name);
		this.sObj = sObj;
	}
	
	public void run(){
		int i=0;
		while(i<10){
			sObj.add(); // 동기화 덧셈호출
			i++;
		}
	}
}

동기화를 사용하지않은 소스코드
synchronized void add(){
를..........
void add() 로 바꿔주고
 
Thread.currentThread().yield(); 를 사용하지않는다... 
 
그러면 스레드 동기화 기능이 사라짐 이렇게 테스트하면됨
 


동기화를  사용하지 않은 결과

 

EunJung : 20
EunJung : 30
EunJung : 40
JiYeon : 20
JiYeon : 60
JiYeon : 70
EunJung : 70
EunJung : 90
EunJung : 100
EunJung : 110
EunJung : 120
EunJung : 130
EunJung : 140
JiYeon : 80
JiYeon : 150
JiYeon : 160
JiYeon : 170
JiYeon : 180
JiYeon : 190
JiYeon : 200


동기화를 사용한 결과

 

JiYeon : 10
JiYeon : 20
JiYeon : 30
JiYeon : 40
JiYeon : 50
JiYeon : 60
JiYeon : 70
JiYeon : 80
JiYeon : 90
JiYeon : 100
EunJung : 110
EunJung : 120
EunJung : 130
EunJung : 140
EunJung : 150
EunJung : 160
EunJung : 170
EunJung : 180
EunJung : 190
EunJung : 200


 

Plus Alpha

 

위에 방법은 메소드로 특정 행동을 정의해놓은것을 불러서 하는 방식이고

변수에만 효과 주려면 이와 같디 하면된다.

 

 

예) buf라는 변수에 zz문자를 추가하는데, 동기화를 시켜서 추가하는

 

    synchronized (buf) {
        buf += "zz";
    }

블로그 이미지

맨오브파워

한계를 뛰어 넘어서..........

,

자바 스윙에서 JFrame, JPanel, JButton, JLabel, JToolBar, JMenu,

                   JDialog,FileDialog,JOptionPane등

 

움직이는 뱀 만들기





import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter;

import java.awt.*;
import java.awt.event.*;
import java.util.Vector;

class HelpDialog extends JDialog{
	JTextField tf;
	
	public HelpDialog(JFrame f, String title, boolean modal){
		super(f, title, modal);
		setLayout(new FlowLayout());
//		add(new JLabel("이것은 뱀게임입니다."));
		tf = new JTextField(10);
		add(tf);
		JButton okBtn = new JButton("OK");
		add(okBtn);
		okBtn.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				setVisible(false);
			}
		});
		setSize(150,100);
	}
	int getValue(){
		String s = tf.getText();
		if(s.length() == 0)
			return -1;
		else{
			try{
				return Integer.parseInt(s);	
			}catch(NumberFormatException e){
				return -1;
			}
		}
	}
}
public class SnakeFrame extends JFrame{
	Thread snakeThread;
	GroundPanel p;
	
	public SnakeFrame(){
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 종료방법
		Container c = getContentPane();
		p = new GroundPanel(); // 메인패널 생성
		c.add(p, BorderLayout.CENTER);	
		setSize(400,400); // 창크기
		createToolBar(); // 툴바
		createMenu(); // 메뉴
		setVisible(true); // 표시여부
		p.requestFocus(); // 포커스 점령
		snakeThread = new Thread(p); // 스레드 초기화
		snakeThread.start(); // 시작
		
		ToolTipManager tt = ToolTipManager.sharedInstance(); // 툴팁 매니저 설저
		tt.setInitialDelay(5); // 툴 팁 나오는 시간 설정
		tt.setDismissDelay(2000); // 2초후 사라져라
	}
	
	public void createToolBar(){ // 툴바
		
		JToolBar tb = new JToolBar("Snake Controllar");
		tb.setFloatable(false); // 툴바 못움직이기 고정하기
		
		JButton suspendButton = new JButton("Suspend");
		suspendButton.setToolTipText("일시중지 합니다."); // 툴 설명쓰기
		tb.add(suspendButton);
		
		JButton resumeButton = new JButton("Resume");
		resumeButton.setToolTipText("이어하기 합니다."); // 툴 설명쓰기
		tb.add(resumeButton);
		
		tb.addSeparator(new Dimension(100,50));
		JButton plusButton = new JButton("Speed : +");
		
		tb.add(plusButton);
		
		JButton minusButton = new JButton("Speed : -");
		tb.add(minusButton);
		
		JButton helpButton = new JButton("HELP");
		tb.add(helpButton);
		
		
		getContentPane().add(tb,BorderLayout.NORTH);
		
		suspendButton.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				p.suspend();
				p.requestFocus();
			}
		});
		
		resumeButton.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				p.resume();
				p.requestFocus();
			}
		});
		
		plusButton.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				p.speedUp();
				p.requestFocus();
			}
		});
		
		minusButton.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				p.speedDown();
				p.requestFocus();
			}
		});
		
		helpButton.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				
//				HelpDialog d = new HelpDialog( (JFrame)null, 
//				"help dialog", true); // TRUE로하면 MODAL,else:modaless
//				d.setSize(150,100);
//				d.setVisible(true);
//				
//				int n = d.getValue();
//				if(n > 0)
//					p.setDelay(n);
//				p.requestFocus();
				
				//한줄짜리 입력창
				String s = JOptionPane.showInputDialog("Delay값을 입력하세요.");
				int n = Integer.parseInt(s);
				if(n > 0)
					p.setDelay(n);
				p.requestFocus();
				
			}
		});
	}
	
	public void createMenu(){ // 메뉴 등록
		JMenuBar mb = new JMenuBar();
		JMenu fileMenu = new JMenu("파일");
		JMenuItem item1 = new JMenuItem("Thread Resume");
		JMenuItem item2 = new JMenuItem("Thread Suspend");
		JMenuItem item3 = new JMenuItem("Thread Kill");
		JMenuItem item4 = new JMenuItem("Change Background");
		
		mb.add(fileMenu); // 메뉴바에 메뉴를붙여라
		
		fileMenu.add(item1); // 메뉴에 아이템을붙여라
		fileMenu.add(item2);
		fileMenu.addSeparator(); // 줄을 그어라
		fileMenu.add(item3);
		fileMenu.add(item4);
		this.setJMenuBar(mb);
		
		item1.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				p.resume();
			}
		});
		
		item2.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				p.suspend();
			}
		});
		
		item3.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				int res = JOptionPane.showConfirmDialog(
				null, "정말로 뱀을 잡을껍니까?","END?",JOptionPane.YES_NO_OPTION);
				
				if(res == JOptionPane.CLOSED_OPTION || 
						res == JOptionPane.NO_OPTION) // 클로즈를 눌럿다면..
					return;
				else
					snakeThread.interrupt(); // 인터럽트날려죽인다
			}
		});
		
		item4.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e){
				p.suspend();
				
				//파일 다이얼로그 불러오기
				JFileChooser chooser = new JFileChooser();
				FileNameExtensionFilter filter = new FileNameExtensionFilter
				("JPG & GIF", "gif", "jpg");
				chooser.setFileFilter(filter); // 파일필터 지정
				chooser.showOpenDialog(null); 
				String path = chooser.getSelectedFile().getPath(); // 파일 경로 가져와라
				p.setImage(new ImageIcon(path).getImage());
								
				p.resume();
			}
		});
	}
	
	class GroundPanel extends JPanel implements Runnable{
		private boolean suspendFlag = false; // true:suspend
		
		final static int LEFT=0;
		final static int RIGHT =1;
		final static int UP = 2;
		final static int DOWN = 3;
		
		int delay=200;
		
		int direction; // 뱀의 방향
		
		Image img; // 이미지 객체
		
		SnakeBody snakeBody; // 스네이크 객체
		
		public GroundPanel(){
			setLayout(null);
			snakeBody = new SnakeBody(); // 생성자 호출
			snakeBody.addin(this); // 현객체 뱀에 추가

			direction = LEFT;
			this.addKeyListener(new MyKeyListener()); // 리스너 지정
			ImageIcon icon = new ImageIcon("images/back.jpg");
			img = icon.getImage(); // 아이콘을 이미지 객체로 가져옴
			
		}
		
		public void setImage(Image img){ // 배경 변경
			this.img = img;
			repaint();
		}
		
		public void paintComponent(Graphics g){
			super.paintComponent(g); // 부모 페인트 호출
			g.drawImage(img, 0,0, getWidth(), getHeight(), null); // 그림을 그려라 
		}
		
		public void run(){ // 스레드 수행 함수
			
			while(true){
				try{
					checkSuspend(); // 잠자는시간이면 띵겨라
					Thread.sleep(delay);
					snakeBody.move(direction); // 방향대로 움직여라
				}catch(InterruptedException e){
					return; // 만약 리턴이없다면 죽이질못한다
				}
			}
		}	
		
		synchronized void checkSuspend(){
			if(suspendFlag == false){
				return;
			}
			else{
				try{
					wait();
				}catch(InterruptedException e){
					return;
				}
			}
		}
		
		void setDelay(int n){
			delay = n;
		}
		
		void speedUp() {
			if(delay < 10)
				return;
			delay = delay / 2;
		}
		
		void speedDown(){
			delay = delay * 2;
		}
		
		void suspend(){ // 중단
			suspendFlag = true;
		}
		
		synchronized void resume(){ // 재개
			suspendFlag = false;
			notify();
		}
		
		class MyKeyListener extends KeyAdapter{ // 이벤트리스너
			
			public void keyPressed(KeyEvent e){
				switch(e.getKeyCode()){
				
				case KeyEvent.VK_LEFT :
					direction = LEFT;
					break;
					
				case KeyEvent.VK_RIGHT :
					direction = RIGHT;
					break;
					
				case KeyEvent.VK_UP :
					direction = UP;
					break;

				case KeyEvent.VK_DOWN :
					direction = DOWN;
					break;
				}
			}
		}
	}
	
	class SnakeBody{
		Vector<JLabel> v = new Vector<JLabel>();
		ImageIcon icon = new ImageIcon("images/head.jpg"); // 뱀 사진
		public SnakeBody(){
			for(int i=0;i<10;i++){ // 10개의 뱀머리 
				JLabel la = new JLabel(icon);
				la.setSize(20,20);
				la.setToolTipText("전 뱀입니다."); // 마우스 올리면 툴팁띄우기
				la.setLocation(100+i*20, 100);
				v.add(la);
			}
		}
		 
		public void addin(JPanel p){ // 꼬리에 추가
			for(int i=0;i<v.size();i++){
				p.add(v.get(i));
			}
		}
		
		public void move(int direction){ // 뱀이동
			for(int i=v.size()-1;i>0;i--){
				JLabel b = v.get(i);
				JLabel a = v.get(i-1);
				b.setLocation(a.getX(), a.getY());
			}
			
			JLabel head = v.get(0);
			
			switch(direction) { // 뱀 이동 알고리즘
			case GroundPanel.LEFT : 
				head.setLocation(head.getX()-10, head.getY());
				break;
				
			case GroundPanel.RIGHT : 
				head.setLocation(head.getX()+10, head.getY());
				break;
				
			case GroundPanel.UP : 
				head.setLocation(head.getX(), head.getY()-10);
				break;
				
			case GroundPanel.DOWN : 
				head.setLocation(head.getX(), head.getY()+10);
				break;
			}
		}
	}
	
	public static void main(String args[]){
		new SnakeFrame();
	}
}

 

블로그 이미지

맨오브파워

한계를 뛰어 넘어서..........

,
import javax.swing.*;
import java.awt.*;

public class TabbedPaneFrame extends JFrame{
	public TabbedPaneFrame(){
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		createTabbedPane();
		setSize(300,300);
		setVisible(true);
	}
	
	void createTabbedPane(){
		JTabbedPane tPane = new JTabbedPane();
		add(tPane);
		tPane.addTab("박지연", new JLabel(new ImageIcon("images/back.jpg")));
		tPane.addTab("함은정", new JLabel(new ImageIcon("images/kwak.jpg")));
		//tPane.addTab("티아라", new JPanel(new SnakeFrame.GroundPanel()));
	}
	
	public static void main(String args[]){
		new TabbedPaneFrame();
	}
}
블로그 이미지

맨오브파워

한계를 뛰어 넘어서..........

,
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import javax.swing.JApplet;
import javax.swing.JPanel;

public class MyApplet extends JApplet {
 MyPanel p = new MyPanel();

 public MyApplet() {
  setContentPane(p);
 }

 public void init() {
	 // String value = getParameter("font");
	 // p.setFSize(Integer.parseInt(value));	 
	 p.repaint();
 }

 public void start() {
 }

 public void stop() {
 }
}

class MyPanel extends JPanel {
 int fSize = 40;

 public MyPanel() {
  setBackground(Color.YELLOW);
 }

 void setFSize(int s) {
  fSize = s;
 }

 public void paintComponent(Graphics g) 
 {
	  super.paintComponent(g);
	  g.setColor(Color.RED);
	  g.setFont(new Font("Ravie", Font.ITALIC, 40));
	  g.drawString("Hello", 100, 100);
 }
}
블로그 이미지

맨오브파워

한계를 뛰어 넘어서..........

,

Java에서 대량의 자료를 추가/삭제하며 처리하기 위해서는 무엇을 사용해야 할까요?

연구실에서 Java를 한번쯤 공부해 본 사람이라면 보통 “Vector Class”라고 대답을 할 것입니다. 정답이죠. Vector Class는 대량의 자료를 가질수 있으며, 추가/삭제또한 자유롭게 처리가 가능합니다. 그럼 뭐가 문제라서 이런 글을 쓰는것일까요?

단순히 “처리되는가” 를 넘어서 “빠르게 처리할수 있는가” 를 생각해 본다면,
위에서의 대답 “Vector Class” 는 X에 가까운 답이라고 할 수 있기 때문입니다.

우선, Java에서 제공하는 “대용량 자료처리 개념” 은 여러가지 상위 인터페이스를 통해서 구현할 수 있습니다. (Collection, Iterator, Enumeration, Map등등) 각각 독특한 특징을 가지고 있습니다만, 이번에 다룰 내용은 Collection이하의 객체들이 되겠습니다.(나머지에 대해서도 다음 기회에 이야기 하도록 하겠습니다.)

Collection Interface는 “내부에 포함되는 요소는 순서를 가진다” 라는 특징을 가지고 있습니다. (이와 반대로 포함요소가 순서에 관계없이 저장되는녀석이 Map계열입니다.)
Collection을 계승(상속)해서 실제 구현된 객체들도 여럿 있습니다만, 그중에서도 대표적인 ArrayList, LinkedList, Vector 의 특징을 간단하게 설명하면 다음과 같습니다.
(HashSet, TreeSet같은 특이한 녀석들도 있습니다만… 일반적인 경우에 사용되는 녀석들은 아닌관계로, 설명은 다음기회로 넘기겠습니다…)

사용자 삽입 이미지

1. Vector

Java 1.0때 만들어져, 지금까지 유지되어온 클래스.
1.0버젼에서는 지금과 같은 List관련 객체들은 없었습니다.
이 버젼대에서 애용되었던 것이 Vector입니다.

Vector의 기본적인 동작은 다음에 설명할 ArrayList와 동일하기 때문에 넘어가기로 하고, 다른점만 설명하겠습니다.
Vector와 이후에 등장하는 List객체의 다른점은 “동기화(synchronize)”처리에 있습니다.
우선 “동기화” 라고 하는 개념에 대해서 간단하게 짚고 넘어가도록 하겠습니다.

두명의 학생이 하나의 컴퓨터를 사용하려고 합니다. 사용순서에 제한이 없기 때문에 서로 먼저 사용하려고 싸우게 되죠. 그러다보니 다음과 같은 상황이 발생합니다. 학생A가 워드로 “가나다라마바사…. ”를 적고 있는도중에 학생B가 키보드를 가로채서 “ABCDEFG…”를 입력해 버립니다. 두 학생은 하나의 자원(컴퓨터)를 공유하지만, 사용 순서에 대한 제한이 전혀 없기때문에 서로 상대방의 자료를 덮어써 버리는 일이 발생하게 되죠.
이것을 방지하기 위해서 자바에서는 synchronized 라는 키워드를 만들어 두었습니다. 이 키워드를 사용하면 공통된 자원에 접근하는것은 [반드시 한번에 하나!] 라는 조건이 붙게 되죠. 한 스레드(학생A)이 공유자원(컴퓨터)에 작업을 마치기 전 까지는 다른 스레드(학생B)가 공유자원(컴퓨터)에 접근을 할 수 없도록 약속해 버리는 것입니다. 이런 과정을 “동기화” 라고 합니다.

복수의 스레드로부터 데이터의 추가/삭제처리가 이루어졌을경우에도 내부의 데이터는 “안전”하게 한번에 한 스레드씩 처리가 이루어지도록 되어있다는 것이죠. 데이터의 안정성을 놓고 보았을때, 정말 좋은 일이 아닐수 없습니다.
… 만, 동기화가 문제시 되는 경우는 어디까지나 “공유자원”과 “복수사용자” 가 존재할때 성립되는 것입니다. 한개의 자원을 하나의 스레드가 사용하는 경우에도 동기화를 고려해서 처리를 하게 되면, 오히려 성능의 저하를 가져오게 되는 문제가 발생하죠. Vector의 경우는 “무조건 동기화” 이기 때문에 단일 스레드 처리에서는 앞으로 설명할 ArrayList나 LinkedList보다 성능이 떨어집니다. 자바 1.2 부터의 Vector의 주 사용목적은 1.0버젼과의 호환성이라고 생각하시는게 가장 좋을겁니다. 거의 쓸 일이 없다는 거죠. 혹시 동기화처리가 필요한 경우는 Vector를 이용하기 보다는 Collection. synchronizedCollection(Collection c)나synchronizedList, Map을 이용하는것이 성능상 바람직하겠습니다.

2. ArrayList

Java2 (1.2)에서 새로이 도입된 Collection의 구현객체입니다.

자료의 추가/삭제 등 기본적인 기능은 Vector와 동일하나, 내부적인 자동 동기화 기능이 삭제되어있죠. 때문에 다수의 스레드 환경에서 사용하기 위해서는 Vector설명에서 이야기했었던 Collection. synchronizedCollection(Collection c)를 이용해서 동기화 옵션을 설정해 주면 됩니다.
이름에서 알 수 있듯이, 내부적으로 자료를 Array(배열)구조로 가지고 있는 객체이죠. 데이터의 추가 / 삭제를 위해서 내부적 임시배열을 작성후 데이터를 복사하는 방법을 사용하고 있습니다.

사용자 삽입 이미지

때문에, 대량의 자료를 추가 / 삭제하는 경우에 내부적인 처리량이 늘어나서 상당한 성능저하를 가져옵니다. (C에서 배열에 데이터 추가/삭제 해 보신분은 아시리라 믿습니다.)
대신, 각 데이터의 인덱스를 가지고 있기 때문에, 필요한 데이터에의 접근이 한번만에 가능하죠. (C에서 포인터를 이용해서 한방에 원하는 데이터에 접근하는것과 같습니다.)
보통, 많은 데이터를 한번에 몽땅 가져와서 여러번 참조해 쓸 때 최상의 성능을 나타내는 객체가 되겠습니다.
간단한 예로 정리를 하면,
물건을 사기위해서 5명의 사람이(손님 A,B,C,D,E) 의자에 앉아 차례를 기다리고 있는데,미리 순서를 예약해 둔 F라는 사람이 C의 앞에 불쑥 들어서서 자리를 비켜달라고 합니다. 예약을 했기때문에 C는 비켜야 하죠. 결국, C는 D의 자리로. D는 다시 E손님의 자리로 한칸씩 밀려나게 됩니다. 그럼 E는? 의자 옆에 빈 공간에 쭈그려 앉던지, 아니면 새로 의자를 요구해야 하겠죠.
이런 손님이 몇백명 있을경우에 도중에 한사람이 끼어들게 되면 뒤로 밀려야 할 사람의 수가 장난이 아니겠죠? 그런 처리를 내부적으로 해 주는것이 ArrayList객체가 되겠습니다.

 

3. LinkedList

연구실에서 C를 배우고 계시거나, 이미 C단계를 지나신 분들이 이해하기 쉬운 말로 바꾸면 “연결리스트” 입니다. 앞과 뒤의 구조체 주소를 가진 녀석들이 죽 ~ 나열된 모습. 그것이 바로 LinkedList객체의 실체입니다.

사용자 삽입 이미지

LinkedList의 내부구현


이녀석은 순서대로 늘어선 것이 아니라, 다음에 나올 자료의 위치정보만 가지고 있습니다. (앞과 뒤 모두 가진 객체도 있습니다.) 자기가 몇번째인지의 정보는 관심도 없죠.
Vector, ArrayList같이 인덱스정보를 가진 녀석들과의 차이점은 무엇일까요?
바로 추가 / 삭제의 용이함에 있습니다.

사용자 삽입 이미지

LinkedList에서의 데이터 추가


위의 그림에서 알 수 있듯이, 어떤 정보를 도중에 추가하기 위해서 다른 정보들을 뒤로 밀어내는 처리가 필요없습니다. 간단하게 글로 표현해 보면,
A-B-C-D 4명이 눈을 가린채, 서로 손을 잡고 있다고 하죠. 손을 잡기 전에 서로 다음에 오는 사람이 누군지만 확인을 한 상황입니다. 이 상태에서 E라는 사람을 B다음에 세우려면 어떻게 해야 할까요?
간단합니다. B의 손을C가 아닌 E를 잡도록 하고, E의 손이 C를 잡도록 살짝~ 도와만 주면 끝입니다. 요것이 LinkedList내부의 추가 처리입니다.(삭제는 역순임으로 설명은 생략)
데이터의 추가가 빈번하게 일어나는 자료를 처리하기 위한 객체라고 할 수 있습니다. 하지만, 데이터의 검색면에서는 어떨까요?

사용자 삽입 이미지

LinkedList에서의 데이터 검색

조금전의 예 – 손을 마주잡고있는 사람들 A-B-E-C-D 중에서 C를 찾아내서 물어볼것이 있습니다. 이 경우 어떻게 해야 하나요? ArrayList의 경우는 “몇번째 녀석이 C이다. “ 라는 목록을 내부적으로 가지고 있기 때문에 한번에 접근이 가능합니다. ... 만, LinkedList는 그런 목록을 가지고 있지 않기때문에, 최초의 정보A로부터 하나씩 검토를 해 나가야만 합니다.
A에게가서 C의 위치를 물어봐도 A는 B가 어디있는지 밖에 모르기때문에 B에게 가서 다시 C의 위치를 물어봐야 합니다. B는 E의 위치밖에 모르니 E에게 가서 또 물어봐야 하죠. 결국 E가 C의 위치를 알려주게 됩니다만… 확률적으로 n개의 데이터가 들어있을경우에 운이 좋으면 1번에, 운이 나쁜경우는 n번 움직여야만 원하는 데이터를 찾을 수 있게 됩니다. 데이터의 검색에는 그다지 적합하지 않은 녀석이죠.
(자료구조 같은 과목에서 검색패턴에 대한 좋은 이야기를 많이 들을 수 있을거에용~ ^^)

이야기를 정리하면,

  • Vector – 구버젼 호환용. 그다지 사용되지 않음. 동기화 처리가 내부적으로 일어남으로 다른 객체보다 무거움.

  • ArrayList – 배열의 복사에 의한 데이터 저장처리를 내부적으로 행하며, 각 데이터에 대한 인덱스를 가지고 있기때문에 검색이 매우 빠르다. 다만, 많은 데이터의 추가 / 삭제시에는 배열의 복사가 빈번하게 일어나, 성능이 떨어지는 단점이 있다.

  • LinkedList – 다음 자료의 위치정보를 가지며, 내부적인 인덱스는 가지고 있지않다. 데이터의 추가 / 삭제는 위치정보의 수정만으로 가능하기 때문에 많은 정보의 추가 / 삭제처리가 필요할때 유용하다. 다만, 데이터가 많은 경우의 검색시 처음 자료로부터 순차적으로 찾아 나가야 하기 때문에 느려지는 단점이 있다.

아직 설명하지 못한 많은 저장 객체들이 존재합니다만…
일반적으로 사용되는 3가지에 대해서 간단하게 적어보았습니다.
왜 비슷한 기능을 가진 녀석들이 여러개 존재하는걸까~ 라고 생각하신다면 각각의 객체가 가지는 특징과 성능차에 대해서 공부해 보는것도 좋을거라고 생각합니다.

실제로 프로그램이라는건 “동작” 하는건 당연한거죠. 보다 좋은 “성능”을 낼 수 있느냐가 중요하다고 생각합니다.
0.01초의 성능차이도 동작하는 환경에 따라서는 생명선이 될 수도 있으니까요.

모두들 좀 더 재밌게~ 그리고 깊게 공부하시는데 조금이나마 보탬이 되었으면~

하는 마음에서 간단하게 적어보았습니다. ~  m(_ _)m

원본 - http://shagall.tistory.com/36

블로그 이미지

맨오브파워

한계를 뛰어 넘어서..........

,