Java 다중 스레드 동시 협업 생산자-소비자 디자인 패턴
두 개의 스레드, 하나의 생산자 및 하나의 소비자
수요 시나리오
두 개의 스레드, 하나는 생산을 담당하고 다른 하나는 소비를 담당합니다.
관련 문제
동기화 문제: 여러 스레드가 동시에 액세스할 때 동일한 리소스의 무결성을 보장하는 방법. 일반적으로 사용되는 동기화 방법은 표시 또는 잠금 메커니즘을 사용하는 것입니다
wait() / nofity() 메소드는 기본 클래스 Object의 두 가지 메소드이므로 모든 Java 클래스가 이 두 가지 메소드를 갖습니다. , 우리는 모든 객체에 대해 동기화 메커니즘을 구현할 수 있습니다.
Wait() 메서드: 버퍼가 가득 차거나 비면 생산자/소비자 스레드는 자체 실행을 중지하고 잠금을 포기하고 대기 상태에 들어가 다른 스레드가 실행되도록 허용합니다.
Notify() 메서드: 생산자/소비자가 제품을 버퍼에 넣거나 꺼낼 때 대기 중인 다른 스레드에 실행 가능한 알림을 보내는 동시에 잠금을 포기하고 자신을 대기 상태.
코드 구현(총 3개 클래스와 메인 메소드가 포함된 테스트 클래스)
Resource.java /** * Created by yuandl on 2016-10-11./** * 资源 */ public class Resource { /*资源序号*/ private int number = 0; /*资源标记*/ private boolean flag = false; /** * 生产资源 */ public synchronized void create() { if (flag) {//先判断标记是否已经生产了,如果已经生产,等待消费; try { wait();//让生产线程等待 } catch (InterruptedException e) { e.printStackTrace(); } } number++;//生产一个 System.out.println(Thread.currentThread().getName() + "生产者------------" + number); flag = true;//将资源标记为已经生产 notify();//唤醒在等待操作资源的线程(队列) } /** * 消费资源 */ public synchronized void destroy() { if (!flag) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName() + "消费者****" + number); flag = false; notify(); } }
Producer.java
/** * Created by yuandl on 2016-10-11. * /** * 生产者 */ public class Producer implements Runnable { private Resource resource; public Producer(Resource resource) { this.resource = resource; } @Override public void run() { while (true) { try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } resource.create(); } } }
Consumer.java
/** * 消费者 */ public class Consumer implements Runnable { private Resource resource; public Consumer(Resource resource) { this.resource = resource; } @Override public void run() { while (true) { try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } resource.destroy(); } } }
ProducerConsumerTest.java
/** * Created by yuandl on 2016-10-11. */ public class ProducerConsumerTest { public static void main(String args[]) { Resource resource = new Resource(); new Thread(new Producer(resource)).start();//生产者线程 new Thread(new Consumer(resource)).start();//消费者线程 } }
인쇄 결과
Thread-0生产者------------1 Thread-1消费者****1 Thread-0生产者------------2 Thread-1消费者****2 Thread-0生产者------------3 Thread-1消费者****3 Thread-0生产者------------4 Thread-1消费者****4 Thread-0生产者------------5 Thread-1消费者****5 Thread-0生产者------------6 Thread-1消费者****6 Thread-0生产者------------7 Thread-1消费者****7 Thread-0生产者------------8 Thread-1消费者****8 Thread-0生产者------------9 Thread-1消费者****9 Thread-0生产者------------10 Thread-1消费者****10
위의 인쇄 결과는 문제가 없음을 보여줍니다
다중 스레드, 다중 생산자 및 다중 소비자 문제
수요 시나리오
4개의 스레드, 2개가 생산을 담당하고, 2개가 소비를 담당하고, 생산자가 1개를 생산하고, 소비자가 1개를 소비합니다.
관련 문제
informAll() 메소드: 생산자/소비자가 버퍼에서 제품을 넣거나 꺼낼 때 다른 모든 대기 스레드에 실행 가능한 알림을 보내는 동시에 잠금을 포기하고 대기 상태에 들어갑니다.
코드 다시 테스트
ProducerConsumerTest.java /** * Created by yuandl on 2016-10-11. */ public class ProducerConsumerTest { public static void main(String args[]) { Resource resource = new Resource(); new Thread(new Consumer(resource)).start();//生产者线程 new Thread(new Consumer(resource)).start();//生产者线程 new Thread(new Producer(resource)).start();//消费者线程 new Thread(new Producer(resource)).start();//消费者线程 } }
실행 결과
Thread-0生产者------------100 Thread-3消费者****100 Thread-0生产者------------101 Thread-3消费者****101 Thread-2消费者****101 Thread-1生产者------------102 Thread-3消费者****102 Thread-0生产者------------103 Thread-2消费者****103 Thread-1生产者------------104 Thread-3消费者****104 Thread-1生产者------------105 Thread-0生产者------------106 Thread-2消费者****106 Thread-1生产者------------107 Thread-3消费者****107 Thread-0生产者------------108 Thread-2消费者****108 Thread-0生产者------------109 Thread-2消费者****109 Thread-1生产者------------110 Thread-3消费者****110
위 인쇄 결과
101 한 번 생산되고 두 번 소비됨
105 생산되었으나 소비되지 않음
이유 분석
두 개일 때 이는 두 개의 스레드가 생산자 생산 또는 소비자 소비를 동시에 수행하는데, 생산자가 있거나 두 개의 스레드가 있으면 wait()를 다시 통지()하는 이유는 한 스레드가 표시를 변경하고 다른 스레드가 직접 계속 실행하기 때문입니다. 판단 표시가 없는 것.
판단 표시가 한 번만 발생하면 실행해서는 안되는 스레드가 실행됩니다. 데이터 오류가 발생했습니다.
솔루션
while 판단 표시는 스레드가 실행 권한을 얻은 후 실행을 원하는지 여부에 대한 문제를 해결합니다. 즉, wait() 이후에 inform()이 실행될 때마다 표시가 나타납니다!
코드 개선(if->Resource에 있는 동안)
Resource.java
/** * Created by yuandl on 2016-10-11./** * 资源 */ public class Resource { /*资源序号*/ private int number = 0; /*资源标记*/ private boolean flag = false; /** * 生产资源 */ public synchronized void create() { while (flag) {//先判断标记是否已经生产了,如果已经生产,等待消费; try { wait();//让生产线程等待 } catch (InterruptedException e) { e.printStackTrace(); } } number++;//生产一个 System.out.println(Thread.currentThread().getName() + "生产者------------" + number); flag = true;//将资源标记为已经生产 notify();//唤醒在等待操作资源的线程(队列) } /** * 消费资源 */ public synchronized void destroy() { while (!flag) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName() + "消费者****" + number); flag = false; notify(); } }
문제가 다시 발견되었습니다
제작 후 74 등 특정 값으로 인쇄하면 프로그램이 잠긴 것처럼 멈춥니다.
원인 분석
알림: 스레드 하나만 깨울 수 있습니다. 이 파티가 이 파티를 깨우면 의미가 없습니다. 또한, while 판단 표시 + 통지는 "교착 상태"를 발생시킵니다.
솔루션
informAll은 자신의 스레드가 상대방의 스레드를 반드시 깨울 수 있는 문제를 해결합니다.
최종 코드 개선(Resource의 notify()->notifyAll())
Resource.java
/** * Created by yuandl on 2016-10-11./** * 资源 */ public class Resource { /*资源序号*/ private int number = 0; /*资源标记*/ private boolean flag = false; /** * 生产资源 */ public synchronized void create() { while (flag) {//先判断标记是否已经生产了,如果已经生产,等待消费; try { wait();//让生产线程等待 } catch (InterruptedException e) { e.printStackTrace(); } } number++;//生产一个 System.out.println(Thread.currentThread().getName() + "生产者------------" + number); flag = true;//将资源标记为已经生产 notifyAll();//唤醒在等待操作资源的线程(队列) } /** * 消费资源 */ public synchronized void destroy() { while (!flag) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName() + "消费者****" + number); flag = false; notifyAll(); } }
실행결과
Thread-0生产者------------412 Thread-2消费者****412 Thread-0生产者------------413 Thread-3消费者****413 Thread-1生产者------------414 Thread-2消费者****414 Thread-1生产者------------415 Thread-2消费者****415 Thread-0生产者------------416 Thread-3消费者****416 Thread-1生产者------------417 Thread-3消费者****417 Thread-0生产者------------418 Thread-2消费者****418 Thread-0生产者------------419 Thread-3消费者****419 Thread-1生产者------------420 Thread-2消费者****420
위 작업은 문제없이 완료되었습니다

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제











JavaScript 문자열 교체 방법 및 FAQ에 대한 자세한 설명 이 기사는 JavaScript에서 문자열 문자를 대체하는 두 가지 방법 인 내부 JavaScript 코드와 웹 페이지의 내부 HTML을 탐색합니다. JavaScript 코드 내부의 문자열을 교체하십시오 가장 직접적인 방법은 대체 () 메소드를 사용하는 것입니다. str = str.replace ( "find", "replace"); 이 메소드는 첫 번째 일치 만 대체합니다. 모든 경기를 교체하려면 정규 표현식을 사용하고 전역 플래그 g를 추가하십시오. str = str.replace (/fi

기사는 JavaScript 라이브러리 작성, 게시 및 유지 관리, 계획, 개발, 테스트, 문서 및 홍보 전략에 중점을 둡니다.

이 기사는 브라우저에서 JavaScript 성능을 최적화하기위한 전략에 대해 설명하고 실행 시간을 줄이고 페이지로드 속도에 미치는 영향을 최소화하는 데 중점을 둡니다.

이 기사는 브라우저 개발자 도구를 사용하여 효과적인 JavaScript 디버깅, 중단 점 설정, 콘솔 사용 및 성능 분석에 중점을 둡니다.

이 기사는 스크립트의 성능을 크게 향상시키기위한 10 가지 간단한 단계를 간략하게 설명합니다. 이러한 기술은 간단하고 모든 기술 수준에 적용 할 수 있습니다. 계속 업데이트 : Vite와 같은 번들과 함께 NPM과 같은 패키지 관리자를 활용하여

프론트 엔드 개발시 프론트 엔드 열지대 티켓 인쇄를위한 자주 묻는 질문과 솔루션, 티켓 인쇄는 일반적인 요구 사항입니다. 그러나 많은 개발자들이 구현하고 있습니다 ...

속편은 약속 기반 Node.js ORM입니다. PostgreSQL, MySQL, MariaDB, Sqlite 및 MSSQL과 함께 사용할 수 있습니다. 이 튜토리얼에서는 웹 앱 사용자를위한 인증을 구현할 것입니다. 그리고 우리는 인기 인증 중간 인 여권을 사용할 것입니다

이 기사에서는 jQuery 라이브러리를 사용하여 간단한 사진 회전 목마를 만들도록 안내합니다. jQuery를 기반으로 구축 된 BXSLIDER 라이브러리를 사용하고 회전 목마를 설정하기위한 많은 구성 옵션을 제공합니다. 요즘 그림 회전 목마는 웹 사이트에서 필수 기능이되었습니다. 한 사진은 천 단어보다 낫습니다! 그림 회전 목마를 사용하기로 결정한 후 다음 질문은 그것을 만드는 방법입니다. 먼저 고품질 고해상도 사진을 수집해야합니다. 다음으로 HTML과 일부 JavaScript 코드를 사용하여 사진 회전 목마를 만들어야합니다. 웹에는 다양한 방식으로 회전 목마를 만드는 데 도움이되는 라이브러리가 많이 있습니다. 오픈 소스 BXSLIDER 라이브러리를 사용할 것입니다. BXSLIDER 라이브러리는 반응 형 디자인을 지원 하므로이 라이브러리로 제작 된 회전 목마는
