● 스레드 스케줄링
스레드의 개수가 코어의 수보다 많을 경우 스레드를 어떤 순서에 의해 동시성으로 실행할 것인지를 계획하는 것입니다.
아주 짧은 시간에 스레드의 run 메서드를 번갈아가면서 실행합니다.
* 스레드 이름 확인하는 방법
class ThreadA extends Thread {
public ThreadA(){
setName("ThreadA"); // 스레드 이름을 설정
}
@Override
public void run() {
for (int i=0; i<10; i++){
System.out.println(getName() + "스레드가 출력합니다.");
}
}
}
class ThreadB extends Thread{
@Override
public void run() {
for (int i=0; i<10; i++){
System.out.println(getName() + "스레드가 출력합니다.");
}
}
}
public class Thread4 {
public static void main(String[] args) {
Thread mainThread = Thread.currentThread(); // currentThread 현재의 스레드가 무엇인지 확인
System.out.println("프로그램 시작");
System.out.println("현재 스레드 이름 : " + mainThread.getName());
ThreadA thA = new ThreadA();
System.out.println("작업 스레드 이름 : " + thA.getName());
thA.start();
ThreadB thB = new ThreadB();
System.out.println("작업 스레드 이름 : " + thB.getName());
thB.start();
}
}
● 우선 순위(priority) 방식
1. 우선 순위가 높은 스레드가 실행상태를 더 많이 가져갑니다.
2. 객체에 우선 순위를 부여하여 개발자가 제어를 합니다.
3. 1부터 10까지 우선순위, 높으면 먼저 실행합니다.
예) thread.setPriority(우선순위값);
* 우선순위가 높은 스레드가 실행 기회를 더 많이 가지기 때문에 우선순위가 낮은 스레드보다
작업을 하더라도 빨리 끝낼 수 있습니다.(작업량에 따라 다름)
class CalcThread extends Thread{
public CalcThread(String name){
setName(name); // th0 th1 th2 ... th9
}
public void run(){
for (int i=0; i<100000; i++){
System.out.println(getName());
}
}
}
public class Thread5 {
public static void main(String[] args) {
for (int i=0; i<10; i++){
Thread th = new CalcThread("th"+i);
if (i == 9){
th.setPriority(Thread.MAX_PRIORITY); // MAX_PRIORITY : 10
}else{
th.setPriority(Thread.MIN_PRIORITY); // MIN_PRIORITY : 1 // NORM_PRIORITY(5)
}
th.start();
}
}
}
● 동기화
1. thread1 필드 값을 변경
2. thread2 필드 값을 변경
3. thread1 필드의 값을 사용
4. 문제 발생!
* 해결 방법 : synchronized 메소드로 해결합니다.
* synchronized : 객체에 잠금을 걸어두어 하나의 스레드만이 접근 가능하고
나머지 스레드는 대기하도록 만듭니다. (임계영역 : 단 하나의 스레드만 실행 할 수 있는 영역)
method() 계산에 관련된 메소드가 있을때에는 동기화가 필요하다.
1) MyCount 생성
public class MyCount {
private int cnt;
public int getCnt() {
return cnt;
}
public void setCnt(int cnt) {
this.cnt = cnt;
}
public synchronized void increment(){ // synchronized 추가
cnt++;
}
}
2) CountThread 생성 Thread 상속
public class CountThread extends Thread {
MyCount counter;
int num;
public CountThread(MyCount counter, int num) {
this.counter = counter;
this.num = num;
}
public void run() {
synchronized (counter) { // synchronized 추가
counter.setCnt(num); // MyCounter 에 값을 세팅
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(getName() + " cnt : " + counter.getCnt());
}
}
}
3) main
public class Thread6 {
public static void main(String[] args) {
MyCount counter = new MyCount();
Thread th1 = new CountThread(counter, 100);
th1.setName("첫번째 스레드");
Thread th2 = new CountThread(counter, 200);
th2.setName("두번째 스레드");
th1.start();
th2.start();
System.out.println("counter cnt : " + counter.getCnt());
}
}
* join() : 다른 스레드의 종료를 기다립니다.
class SumThread extends Thread {
private long sum;
public long getSum() {
return sum;
}
public void setSum(long sum) {
this.sum = sum;
}
public void run(){
for (int i=0; i<=100; i++){
sum += i;
}
}
public String toString(){
return "스레드 총합 : " + sum;
}
}
public class Thread7 {
public static void main(String[] args) {
System.out.println("메인 스레드 시작");
SumThread sumThread = new SumThread();
sumThread.start();
try{
sumThread.join();
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println("1~100 합 : " + sumThread.getSum());
}
}
join()을 사용하여 다른 스레드 종료를 기다립니다.
* thread 1, 2, 3을 실행하고 thread3이 제일 먼저 끝나게 됩니다.
thread 1 다음 thread2 다음 thread3 순서로 join을 하여 마지막으로
thread 3이 join되어 결과는 thread3이 처음 또는 두번째로 끝나게 됩니다.
import java.util.concurrent.TimeUnit;
class JoinTask implements Runnable {
private static int count = 0;
private int id;
private long sleepTime;
private String taskId;
@Override
public void run() {
String currentThreadName = Thread.currentThread().getName();
System.out.println("[현재 스레드 이름 : " + currentThreadName + ", " + taskId + " ]");
for (int i = 0; i<4; i++){
System.out.println("[현재 스레드 이름 : " + currentThreadName + ", " + taskId + " ] >> for문");
try{
TimeUnit.MILLISECONDS.sleep(sleepTime);
}catch (InterruptedException e){
e.printStackTrace();
}
}
System.out.println("[현재 스레드 이름 : " + currentThreadName + ", " + taskId + " ] >> 완료");
}
public JoinTask(long sleepTime){
this.id = ++count;
this.taskId = "Task: " + id;
this.sleepTime = sleepTime;
}
}
public class Thread8 {
public static void main(String[] args) throws InterruptedException {
String currentThreadName = Thread.currentThread().getName();
System.out.println("[" + currentThreadName + "]" + " 스레드 시작!");
Thread thread1 = new Thread(new JoinTask(200), "첫번째 스레드");
Thread thread2 = new Thread(new JoinTask(500), "두번째 스레드");
Thread thread3 = new Thread(new JoinTask(100), "세번째 스레드");
thread1.start();
thread2.start();
thread3.start();
thread1.join();
System.out.println("[" + currentThreadName + "]" + " join! " + thread1.getName());
thread2.join();
System.out.println("[" + currentThreadName + "]" + " join! " + thread2.getName());
thread3.join();
System.out.println("[" + currentThreadName + "]" + " join! " + thread3.getName());
System.out.println("[" + currentThreadName + "]" + " 스레드 종료");
}
}
'🎨 Programming > JAVA' 카테고리의 다른 글
[JAVA] 33. 자바 셀레니움(Selenium) (0) | 2021.03.22 |
---|---|
[JAVA] 32. 자바 크롤링(Scraping) (0) | 2021.03.22 |
[JAVA] 30. 스레드(thread) - 1 (0) | 2021.03.22 |
[JAVA] 29. 람다 표현식 (0) | 2021.03.22 |
[JAVA] 28. 중첩 클래스 (0) | 2021.03.22 |