Java 동시 프로그래밍 예시 (7): 수호 스레드 생성 및 실행

Java는 특수한 루틴을 가지고 있습니다. 이 루틴은 우선순위가 매우 낮습니다. 같은 프로그램의 다른 루틴이 실행되지 않을 때만 실행됩니다.
수호 루틴은 이러한 특성을 가지고 있기 때문에 일반적으로 프로그램의 일반 루틴 (사용자 루틴이라고도 부른다) 을 위해 서비스를 제공한다.그것들은 일반적으로 무한 순환이 있거나 요청 서비스를 기다리거나 임무를 수행하는 데 쓰인다.그것들은 어떤 중요한 일도 할 수 없다. 왜냐하면 우리는 그들이 언제 CPU 운행 시간을 분배할 수 있을지 확실하지 않고, 다른 라인이 실행되지 않을 때, 그것들은 자동으로 종료되기 때문이다.이런 라인의 전형적인 응용 프로그램 중 하나는 자바의 쓰레기 회수이다.
이 절의 예시에서 우리는 두 개의 라인을 만들 것이다. 하나는 일반 라인이고 대기열에 이벤트를 쓸 것이다.또 하나는 라인을 지키고 대기열에 있는 이벤트를 지우고 10초 이상 존재하는 이벤트를 삭제하는 것이다.
그 사실을 알다
아래의 절차에 따라 예시 절차를 실현하다.
1. 프로그램 실행에 필요한 이벤트 정보만 저장하는 이벤트 클래스를 만듭니다.두 개의 속성을 성명합니다. 하나는java입니다.util.Date 형식의date는 익숙하고 다른 하나는 String 형식의 이벤트 속성입니다.그리고 이 두 속성을 생성하는 읽기와 쓰기 방법.코드는 다음과 같습니다.

public class Event {
    private Date date;
    private String event;

    public Date getDate() {
        return date;
    }

    public void setDate(Date date) {
        this.date = date;
    }

    public String getEvent() {
        return event;
    }

    public void setEvent(String event) {
        this.event = event;
    }
}

2. WriterTask라는 클래스를 만들고 Runnable 인터페이스를 실현합니다.코드는 다음과 같습니다.

public class WriterTask implements Runnable {
3. 이벤트를 저장하는 데 사용되는 대기열 속성을 설명하고 클래스의 구조 함수를 실현하며 그 매개 변수를 이용하여 대기열 속성을 초기화합니다.코드는 다음과 같습니다.

private Deque<Event> deque;

public WriterTask(Deque<Event> deque) {
    this.deque = deque;
}

4. 이 임무를 실현하는run() 방법은 100번의 순환을 포함한다.매번 훑어볼 때마다 새로운 이벤트 대상을 만들고 대기열에 저장한 다음 1초 동안 잠을 잔다.코드는 다음과 같습니다.

@Override
public void run() {
    for (int i = 0; i < 100; i++) {
        Event event = new Event();
        event.setDate(new Date());
        event.setEvent(String.format("The thread %s has generated an event",
                Thread.currentThread().getId()));
        deque.addFirst(event);
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
5. CleanerTask라는 클래스를 만들고 Thread 클래스를 계승합니다.코드는 다음과 같습니다.

public class CleanerTask extends Thread {
6. 이벤트를 저장하는 데 사용되는 대기열 속성을 설명하고 클래스의 구조 함수를 실현하며 그 매개 변수를 이용하여 대기열 속성을 초기화합니다.구조 방법에서 setDaemon () 방법을 호출하여 이 스레드를 수호 스레드로 설정합니다.코드는 다음과 같습니다.

private Deque<Event> deque;

public CleanerTask(Deque<Event> deque) {
    this.deque = deque;
    setDaemon(true);
}

7. run () 방법을 실현하고 방법 안에 무한 순환이 있어 현재 시간을 얻고 clearn () 방법을 호출합니다.코드는 다음과 같습니다.

@Override
public void run() {
    while (true) {
        Date date = new Date();
        clean(date);
    }
}
8. clean () 방법을 실현합니다. 이 방법에서 맨 뒤에 있는 시간을 가져와서 시간과 현재 시간의 차이를 검사합니다. 10초 전에 만든 경우 현재 이벤트를 삭제하고 다음 이벤트를 검사합니다.이벤트가 삭제되면 삭제된 이벤트에 대한 정보를 출력하고 대기열의 최신 길이를 출력합니다. 그러면 프로그램의 실행 진전을 볼 수 있습니다.코드는 다음과 같습니다.

private void clean(Date date) {
    long difference;
    boolean delete;

    if (deque.size() == 0) {
        return;
    }

    delete = false;
    do {
        Event e = deque.getLast();
        difference = date.getTime() - e.getDate().getTime();
        if (difference > 10000) {
            System.out.printf("Cleaner: %s
", e.getDate());
            deque.removeLast();
            delete = true;
        }
    } while (difference > 10000);

    if (delete) {
        System.out.printf("Clearner: Size of the queue: %d
", deque.size());
    }
}

9. 프로그램의 메인 클래스, 메인 클래스를 만들고 메인 () 방법을 실현합니다.코드는 다음과 같습니다.

public class Main {
    public static void main(String[] args) {
10. Deque 클래스를 사용하여 이벤트를 저장하는 대기열을 만듭니다.코드는 다음과 같습니다.

Deque<Event> deque = new ArrayDeque<>();
11. 세 개의 WriterTask 스레드와 CleanerTask 스레드를 만들고 시작합니다.코드는 다음과 같습니다.

Deque<Event> deque = new ArrayDeque<>();
WriterTask writer = new WriterTask(deque);
for (int i = 0; i < 3; i++) {
    Thread thread = new Thread(writer);
    thread.start();
}

CleanerTask cleaner = new CleanerTask(deque);
cleaner.start();

12. 실행 프로그램, 실행 결과를 보십시오.
그 까닭을 알다
프로그램의 실행 결과를 분석하면 대기열이 먼저 30으로 증가한 다음에 27에서 30 사이에 변화하여 프로그램의 실행이 끝났다는 것을 알 수 있다.
프로그램은 먼저 세 개의 WriterTask 라인부터 실행되며, 각 라인은 먼저 이벤트를 추가한 다음 1초 동안 잠을 잔다.10초 전이 지나면 대기열에 30개의 이벤트가 존재합니다.이 10초 동안 세 개의 WriterTask 스레드가 수면을 취할 때 CleanerTask 스레드가 실행되지만 모든 이벤트의 생성 시간이 10초를 넘지 않기 때문에 어떤 이벤트도 삭제하지 않습니다.10초가 지난 후 1초에 세 개의 WriterTask가 대기열에 세 개의 이벤트를 추가합니다.마찬가지로 CleanerTask는 초당 세 개의 이벤트를 삭제합니다.그래서 사건의 수는 27에서 30 사이를 배회하고 있다.
WriterTask 스레드가 모두 휴면할 때, 우리는 시간을 자유롭게 처리할 수 있으며, 그 동안 수호 스레드가 실행될 수 있습니다.WriterTask 스레드의 수면 시간을 더 짧게 설정하면 CleanerTask 스레드가 CPU 실행 시간을 더 적게 가져옵니다.과연 그렇다면, Cleaner Task 라인이 충분한 실행 시간을 얻지 못해 충분한 이벤트를 삭제하는 데 사용할 수 없기 때문에, 대기열의 길이는 계속 증가할 것이다.
영원히 끝이 없다
start () 방법을 호출하기 전에만 setDaemon () 방법을 호출하여 라인을 수호 라인으로 설정할 수 있습니다.루틴이 실행되기 시작하면 수호 상태를 수정할 수 없습니다.
또한 isDaemon () 을 사용하여 스레드가 수호 스레드인지 확인할 수 있습니다.수호 라인이라면true로 돌아가기;일반 라인이라면false로 돌아갑니다.
나래주의
본고는 《Java7 Concurrency Cookbook》(D 오이고에서 《Java7 병발 예시집》으로 번역)에서 번역한 것으로 학습 자료로만 사용된다.권한이 없으면 어떠한 상업 행위에도 사용할 수 없다.
소소하다
이 절에서 사용하는 모든 예시 코드의 전체 버전입니다.
Event 클래스의 전체 코드

package com.diguage.books.concurrencycookbook.chapter1.recipe7;

import java.util.Date;

/**
 *
 * Date: 2013-09-19
 * Time: 22:56
 */
public class Event {
    private Date date;
    private String event;

    public Date getDate() {
        return date;
    }

    public void setDate(Date date) {
        this.date = date;
    }

    public String getEvent() {
        return event;
    }

    public void setEvent(String event) {
        this.event = event;
    }
}

WriterTask 클래스의 전체 코드

package com.diguage.books.concurrencycookbook.chapter1.recipe7;

import java.util.Date;
import java.util.Deque;
import java.util.concurrent.TimeUnit;

/**
 * 。
 * Date: 2013-09-19
 * Time: 22:59
 */
public class WriterTask implements Runnable {
    private Deque<Event> deque;

    public WriterTask(Deque<Event> deque) {
        this.deque = deque;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            Event event = new Event();
            event.setDate(new Date());
            event.setEvent(String.format("The thread %s has generated an event",
                    Thread.currentThread().getId()));
            deque.addFirst(event);
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

CleanerTask 클래스의 전체 코드

package com.diguage.books.concurrencycookbook.chapter1.recipe7;

import java.util.Date;
import java.util.Deque;

/**
 *
 * Date: 2013-09-19
 * Time: 23:33
 */
public class CleanerTask extends Thread {
    private Deque<Event> deque;

    public CleanerTask(Deque<Event> deque) {
        this.deque = deque;
        setDaemon(true);
    }

    @Override
    public void run() {
        while (true) {
            Date date = new Date();
            clean(date);
        }
    }

    /**
     * 。
     *
     * @param date
     */
    private void clean(Date date) {
        long difference;
        boolean delete;

        if (deque.size() == 0) {
            return;
        }

        delete = false;
        do {
            Event e = deque.getLast();
            difference = date.getTime() - e.getDate().getTime();
            if (difference > 10000) {
                System.out.printf("Cleaner: %s
", e.getDate());
                deque.removeLast();
                delete = true;
            }
        } while (difference > 10000);

        if (delete) {
            System.out.printf("Clearner: Size of the queue: %d
", deque.size());
        }
    }
}

Main 클래스의 전체 코드

package com.diguage.books.concurrencycookbook.chapter1.recipe7;

import java.util.ArrayDeque;
import java.util.Deque;

/**
 * Date: 2013-09-19
 * Time: 23:54
 */
public class Main {
    public static void main(String[] args) {
        Deque<Event> deque = new ArrayDeque<>();
        WriterTask writer = new WriterTask(deque);
        for (int i = 0; i < 3; i++) {
            Thread thread = new Thread(writer);
            thread.start();
        }

        CleanerTask cleaner = new CleanerTask(deque);
        cleaner.start();
    }
}

좋은 웹페이지 즐겨찾기