티스토리 뷰

development/Java

[Java] 쓰레드 Thread

Happyoon ~ 2021. 11. 16. 22:17
728x90
반응형

Thread실행흐름이다.

특별한 설정을 하지 않는 이상, 한 프로세스 당 하나의 스레드가 실행되는데, 예를 들어 큰 용량의 파일을 다운로드할 경우, 스레드가 하나라면 다운로드 되는 동안 다른 작업은 일절 수행할 수 없다.

따라서, 멀티 스레드가 필요한 경우가 많다. 

이번 게시물은 여러개의 스레드를 만드는 예시를 다뤄볼 예정이다.


우선, 스레드를 만드는 두가지 방법을 살펴보자.

- 새로운 스레드 만드는 방법 1

 1. Thread 클래스를 상속 받은 클래스를 정의한다.
 2. run() 메소드를 오버라이드 한다.
 3. run() 메소드 안에서 새로운 스레드에서 해야할 작업을 코딩한다.
 4. 만든 클래스를 객체로 생성하고 해당 객체의 start() 메소드를 호출하면 새로운 스레드가 시작된다 .

 

- 새로운 스레드 만드는 방법 2

 1. Runnable 인터페이스를 구현한 클래스를 정의한다.
 2. run() 메소드를 강제 오버라이드 한다.
 3. Thread 클래스로 객체를 생성하면서 해당클래스로 만든 객체를 생성자의 인자로 전달한다.
 4. Thread 클래스로 만든 객체의 start() 메소드를 호출해서 스레드를 시작 시킨다.


Thread.sleep() 사용해보기

 

Frame01.java

package test.main;


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

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

public class Frame01 extends JFrame implements ActionListener{
	//생성자
	public Frame01() {
		setTitle("Frame01");
		setBounds(100,100,800,500);
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		setLayout(new FlowLayout());
		
		JTextField inputText = new JTextField(10);
		add(inputText);
		
		JButton btn1 = new JButton("눌러보셈");
		add(btn1);
		btn1.addActionListener(this);
		
		setVisible(true);
		
	}
	public static void main(String[] args) {
		new Frame01();
		
		
	}
	@Override
	public void actionPerformed(ActionEvent e) {
		
		System.out.println("버튼을 눌렀네요!");
		try {
			//완료하는데 10초가 걸리는 작업을 한다고 가정하자.
			Thread.sleep(10000);
		} catch (InterruptedException e1) {
			e1.printStackTrace();
		}
		System.out.println("actionPerformed 메소드가 종료됩니다.");
		
	}
}

버튼을 누르면 10초가 걸리는 작업이 수행되고, 해당 작업이 수행되는 동안 다른 작업은 불가하다.


새 스레드 생성하고, 스레드에서 생성할 내용 클래스로 만들기

 

다운로드를 하는 클래스를 따로 만들어보자.

 

DownloadThread.java

package test.mypac;
/*
 * 새로운 스레드 만드는 법
 * 1. Thread 클래스를 상속 받은 클래스를 정의한다.
 * 2. run() 메소드를 오버라이드 한다.
 * 3. run() 메소드 안에서 새로운 스레드에서 해야할 작업을 코딩한다.
 * 4. 만든 클래스를 객체로 생성하고 해당 객체의 start() 메소드를 호출하면
 * 새로운 스레드가 시작된다 
 */

public class DownloadThread extends Thread{
	@Override
	public void run() {
		try {
			//완료하는데 3초가 걸리는 작업을 한다고 가정하자.
			Thread.sleep(3000);
			System.out.println("다운로드가 완료 되었습니다.");
		} catch (InterruptedException e1) {
			e1.printStackTrace();
		}
		
	}

}

Frame02.java

package test.main;


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

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

import test.mypac.DownloadThread;

public class Frame02 extends JFrame implements ActionListener{
	//생성자
	public Frame02() {
		setTitle("Frame02");
		setBounds(100,100,800,500);
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		setLayout(new FlowLayout());
		
		JTextField inputText = new JTextField(10);
		add(inputText);
		
		JButton btn1 = new JButton("눌러보셈");
		add(btn1);
		btn1.addActionListener(this);
		
		setVisible(true);
		
	}
	public static void main(String[] args) {
		new Frame02();
		
		
	}
	@Override
	public void actionPerformed(ActionEvent e) {
		System.out.println("버튼을 눌렀네요!");
		new DownloadThread().start();
		System.out.println("actionPerformed 메소드가 종료됩니다.");
		
		
	}
}

이너클래스로 스레드 생성하기

이너클래스로 스레드를 생성할 수 있다.

스레드일회용이라 변수에 담아 재사용이 불가하므로 필요할 때마다 new 해서 사용해야 한다. 

new 로 생성한 스레드는 모양이 같아도 각각의 독립적인 스레드이다.

Frame03.java

package test.main;

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

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

import test.mypac.DownloadThread;

public class Frame03 extends JFrame implements ActionListener {
	// 생성자
	public Frame03() {
		setTitle("Frame03");
		setBounds(100, 100, 800, 500);
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		setLayout(new FlowLayout());

		JTextField inputText = new JTextField(10);
		add(inputText);

		JButton btn1 = new JButton("눌러보셈");
		add(btn1);
		btn1.addActionListener(this);

		setVisible(true);

	}

	public static void main(String[] args) {
		new Frame03();
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		System.out.println("버튼을 눌렀네요!");
		new DownloadThread().start();
		new DownloadThread().start();//스레드는 일회용, 각각 독립적
		//스레드는 일회용이므로 변수에 담아 재사용 불가하므로 필요할 때마다 new해서 사용
		System.out.println("actionPerformed 메소드가 종료됩니다.");

	}

	class DownloadThread extends Thread{
		@Override
		public void run() {
			try {
				//완료하는데 3초가 걸리는 작업을 한다고 가정하자.
				Thread.sleep(3000);
				System.out.println("다운로드가 완료 되었습니다.");
			} catch (InterruptedException e1) {
				e1.printStackTrace();
			}
			
		}
	}
}

익명의 local inner class 로 스레드 생성하기

 

Frame04.java

package test.main;

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

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

import test.mypac.DownloadThread;

public class Frame04 extends JFrame implements ActionListener {
	// 생성자
	public Frame04() {
		setTitle("Frame04");
		setBounds(100, 100, 800, 500);
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		setLayout(new FlowLayout());

		JTextField inputText = new JTextField(10);
		add(inputText);

		JButton btn1 = new JButton("눌러보셈");
		add(btn1);
		btn1.addActionListener(this);

		setVisible(true);

	}

	public static void main(String[] args) {
		new Frame04();
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		System.out.println("버튼을 눌렀네요!");
		
		Thread t = new Thread() {
			@Override
			public void run() {
				try {
					//완료하는데 3초가 걸리는 작업을 한다고 가정하자.
					Thread.sleep(3000);
					System.out.println("다운로드가 완료 되었습니다.");
				} catch (InterruptedException e1) {
					e1.printStackTrace();
				}
				
			}
			
		};
		t.start();
		System.out.println("actionPerformed 메소드가 종료됩니다.");

	}
}

변수에 담지 않고 local inner class로 스레드 생성하기

 

Frame05.java

package test.main;

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

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

import test.mypac.DownloadThread;

public class Frame05 extends JFrame implements ActionListener {
	// 생성자
	public Frame05() {
		setTitle("Frame05");
		setBounds(100, 100, 800, 500);
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		setLayout(new FlowLayout());

		JTextField inputText = new JTextField(10);
		add(inputText);

		JButton btn1 = new JButton("눌러보셈");
		add(btn1);
		btn1.addActionListener(this);

		setVisible(true);

	}

	public static void main(String[] args) {
		new Frame05();
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		System.out.println("버튼을 눌렀네요!");

		new Thread() {
			@Override
			public void run() {
				try {
					// 완료하는데 3초가 걸리는 작업을 한다고 가정하자.
					Thread.sleep(3000);
					System.out.println("다운로드가 완료 되었습니다.");
				} catch (InterruptedException e1) {
					e1.printStackTrace();
				}

			}

		}.start();

		System.out.println("actionPerformed 메소드가 종료됩니다.");

	}
}

Runnable 클래스를 만들고 Thread 객체 생성자의 인자로 전달하기 

 

CountRunnable.java

package test.mypac;
/*
 * 새로운 스레드 만드는 방법2
 * 1. Runnable 인터페이스를 구현한 클래스를 정의한다.
 * 2. run() 메소드를 강제 오버라이드한다.
 * 3. Thread 클래스로 객체를 생성하면서 해당 클래스로 만든 객체를 생성자의 인자로 전달한다.
 * 4. Thread 클래스로 만든 객체의 start() 메소드를 호출해서 스레드를 시작시킨다.
 */

public class CountRunnable implements Runnable{

	@Override
	public void run() {
		int count=0;
		while(true) {
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			count++;//카운트를 증가시킨다.
			System.out.println("현재 카운트: "+count);
			if(count==10) break;//카운트가 10이 되면 반복문 탈출 => run() 메소드 종료 => 스레드 종료를 의미
		}
		
	}
	

}

Frame06.java

package test.main;

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

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

import test.mypac.CountRunnable;
import test.mypac.DownloadThread;

public class Frame06 extends JFrame implements ActionListener {
	// 생성자
	public Frame06() {
		setTitle("Frame06");
		setBounds(100, 100, 800, 500);
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		setLayout(new FlowLayout());

		JTextField inputText = new JTextField(10);
		add(inputText);

		JButton btn1 = new JButton("눌러보셈");
		add(btn1);
		btn1.addActionListener(this);

		setVisible(true);

	}

	public static void main(String[] args) {
		new Frame06();
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		System.out.println("버튼을 눌렀네요!");
		
		Thread t = new Thread(new CountRunnable());
		t.start();
			

		System.out.println("actionPerformed 메소드가 종료됩니다.");

	}
}

Runnable을 상속받은 inner class를 생성하여 스레드 생성자의 인자로 전달하기

 

Frame07.java

package test.main;

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

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

import test.mypac.CountRunnable;
import test.mypac.DownloadThread;

public class Frame07 extends JFrame implements ActionListener {
	// 생성자
	public Frame07() {
		setTitle("Frame07");
		setBounds(100, 100, 800, 500);
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		setLayout(new FlowLayout());

		JTextField inputText = new JTextField(10);
		add(inputText);

		JButton btn1 = new JButton("눌러보셈");
		add(btn1);
		btn1.addActionListener(this);

		setVisible(true);

	}

	public static void main(String[] args) {
		new Frame07();
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		System.out.println("버튼을 눌렀네요!");

		Thread t = new Thread(new Runnable() {

			@Override
			public void run() {
				int count = 0;
				while (true) {
					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					count++;// 카운트를 증가시킨다.
					System.out.println("현재 카운트: " + count);
					if (count == 10)
						break;// 카운트가 10이 되면 반복문 탈출 => run() 메소드 종료 => 스레드 종료를 의미
				}

			}
		});
		t.start();

		System.out.println("actionPerformed 메소드가 종료됩니다.");

	}
}

Frame7을 lambda 식으로 표현하기

 

Frame09.java

package test.main;

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

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

import test.mypac.CountRunnable;
import test.mypac.DownloadThread;

public class Frame09 extends JFrame implements ActionListener {
	// 생성자
	public Frame09() {
		setTitle("Frame09");
		setBounds(100, 100, 800, 500);
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		setLayout(new FlowLayout());

		JTextField inputText = new JTextField(10);
		add(inputText);

		JButton btn1 = new JButton("눌러보셈");
		add(btn1);
		btn1.addActionListener(this);

		setVisible(true);

	}

	public static void main(String[] args) {
		new Frame09();
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		System.out.println("버튼을 눌렀네요!");

		new Thread(() -> {
			int count = 0;
			while (true) {
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e2) {
					e2.printStackTrace();
				}
				count++;// 카운트를 증가시킨다.
				System.out.println("현재 카운트: " + count);
				if (count == 10)
					break;// 카운트가 10이 되면 반복문 탈출 => run() 메소드 종료 => 스레드 종료를 의미
			}

		}).start();

		System.out.println("actionPerformed 메소드가 종료됩니다.");

	}
}

 

반응형

'development > Java' 카테고리의 다른 글

[Java] JFrame #2 예제  (2) 2021.11.16
[Java] JFrame #1  (0) 2021.11.16
[Java] Java template 만들기  (0) 2021.11.13
[Java] JDBC #2 DAO  (0) 2021.11.13
[Java] JDBC #1 / DB 연결, SELECT, INSERT, DELETE, UPDATE, DTO  (1) 2021.11.11
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
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 31
글 보관함