스레드는 생각하는대로 재사용 할 수 없습니다. 실제로 숫자를 생성 할 때마다 신선한 스레드를 실제로 시작하고 있습니다. 이 시점에서 계산을위한 별도의 스레드가 전혀 없을 수도 있습니다.
질문의 하위 텍스트는 항상 3 개의 스레드가 실행 중임을 나타냅니다. 그것은 당신의 문제를 본질적으로 두 소비자의 생산자가되게합니다. 유일한 단서는 소비자가 지능적으로 행동하고 필요한 데이터 만 수집해야한다는 것입니다.
처리 코드는 올바른 트랙에서 꺼져 있습니다. 새로운 스레드를 시작하는 대신 notify
(실제로는 notifyAll
) 스레드는 Even
및 Odd
을 실행해야합니다.
매초마다 하나의 항목을 생성하므로 실제로 적절한 대기열이 필요하지 않습니다. 단일 Integer
개체는 소비되지 않은 번호를 저장하기에 충분합니다. 상대적으로 구형 아키텍처에서도 1 초 이상 걸리면 다른 문제가 발생할 수 있습니다. int
대신 Integer
을 사용하는 이유는 객체가 이미 소비되었음을 대기중인 스레드에 알릴 수 있어야한다는 것입니다.이 경우에는 null
을 반환하는 것이 매우 쉬운 것처럼 보입니다. 생성 된 정수가 peek
및 get
통해 액세스 될 수있는 필드에 배치된다
는
class Producer implements Runnable, IntConsumer
{
private Integer buffer = null;
public void run()
{
new Random().ints().forEach(this);
}
public void accept(int i)
{
synchronized(this) {
this.buffer = i;
this.notifyAll();
}
try {
Thread.sleep(1000L);
} catch(InterruptedException ie) {
throw new RuntimeException("Producer interrupted!");
}
}
public Integer peek()
{
return this.buffer;
}
public synchronized Integer get()
{
Integer i = peek();
this.buffer = null;
return i;
}
}
통지. 버퍼를 지우는 get
처럼 생성 코드가 생성자 객체에 잠급니다. 이렇게하면 한 번에 하나의 엔티티 만 값을 수정할 수 있습니다.
일반적으로 소비자와 제작자는 공유 스택이나 대기열 개체 또는 비슷한 것을 통해 통신합니다. 동기화는 큐에 의해 수행되며 LinkedBlockingQueue
또는 ArrayBlockingQueue
입니다.이 간단한 경우 생성자는 큐 기능을 구현하므로 소비자는 제작자를 인식해야합니다.
소비자 스레드는 많은 공통 기능을 가지고 있습니다. 둘 다 생산자의 통지를 기다려야하고, 잠금 장치를 획득하고, 다음 오브젝트가 사용되지 않아서 속해 있는지 확인한 다음 소비하거나 기다리게해야합니다. 에러를 피하기 위해 check-then-get 연산은 모두 원자 적이어야한다. 이 모든 것은 기본 클래스에서 쉽게 인코딩 될 수 있습니다. 이 클래스는 확인 숫자를 처리하는 추상적 인 방법이있을 것이다 다음 숫자 입력의 패리티, 그리고 그들이에 적합하는 숫자를 처리하는 경우
public abstract class Consumer implements Runnable
{
private final Producer producer;
public Consumer(Producer producer)
{
this.producer = producer;
}
public void run()
{
while(true) {
synchronized(this.producer) {
Integer i = this.producer.peek();
if(i != null && check(i)) {
this.producer.get();
process(i);
}
try {
this.producer.wait();
} catch(InterruptedException ie) {
throw new RuntimeException("Consumer interrupted!");
}
}
}
}
public abstract boolean check(int i);
public abstract void process(int i);
}
구체적인 구현은 확인합니다. check
과 process
은 Integer
대신 int
을 수락함으로써 생산자가 비어 있는지 확인하는 것은 자신의 책임이 아니라는 점을 강조합니다. 마지막으로
public class Even extends Consumer
{
public Even(Producer producer)
{
super(producer);
}
public boolean check(int i)
{
return (i % 2) == 0;
}
public void process(int i)
{
System.out.println("x=" + i + "; x^2=" + (i * i));
}
}
public class Odd extends Consumer
{
public Odd(Producer producer)
{
super(producer);
}
public boolean check(int i)
{
return (i % 2) != 0;
}
public void process(int i)
{
System.out.println("x=" + i + "; x^3=" + (i * i * i));
}
}
함께 모든 것을 묶는 main
방법을 포함하는 드라이버 :
public class Driver
{
public static void main(String[] args)
{
Producer prod = new Producer();
new Thread(new Even(prod)).start();
new Thread(new Odd(prod)).start();
new Thread(prod).start();
}
}
당신은 메인 스레드를 대기, 초기 힘 main
종료에 문제가있는 경우 제작자가 다음과 같이 (영원히) 끝내기 위해 :
Thread t = new Thread(prod);
t.start();
t.join();
는 는 (리눅스 이상에)
Ctrl+C
를 누를 때까지 다음과 같은 출력, 매초마다를 생성합니다 코드
:
x=966307133; x^3=-1676528219
x=1271569805; x^3=-1481001707
x=456385150; x^2=-1701399036
x=-474801821; x^3=-813682373
x=-1046547765; x^3=927976307
x=-148577454; x^2=-185956796
x=-14905035; x^3=-1126539123
x=2071820769; x^3=-1426032223
x=1075272421; x^3=1952259101
x=-895041093; x^3=-978791741
x=-2054472224; x^2=3441664
...
왜 여러 스레드에서이 작업을 수행하고 있습니까? 많은 동시성 문제가 발생할 수 있습니다. 왜 단지 하나의 스레드가 값을 인쇄하지 않는가? – FredK
@FredK 동기화 문제를 만들기 위해 고안된 과제 인 것 같습니다 –
@ 존 과제 였지만 과제를 넘어서 생각하고 있습니다. – Ben