자바 다 중 스 레 드 잠 금 및 Condition 류 사용 사례 분석
인터넷 에서 매우 많은 운행 코드 를 보 았 습 니 다.많은 것 이 중복 되 었 습 니 다.한 가지 더 말씀 드 리 겠 습 니 다.자바 늙 은 새 에 게 자바 의 다 중 스 레 드 를 이해 하 는 것 은 매우 쉬 운 일이 지만 저 같은 풋내기 에 게 이것 은 정말 어렵 습 니 다.제 가 너무 못 했 나 봐 요.인터넷 에서 반복 되 는 진술 은 내 가 이 문 제 를 이해 하 는 데 아무런 도움 이 되 지 않 는 다.그래서 여기 서 나 는 이 문제 에 대한 이 해 를 적 었 다.그 목적 은 내 가 잊 지 않도록 하기 위해 서 이다.
아니면 코드 인 스 턴 스 부터 말 할 까요?
코드
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Predicate;
public class Main {
public static void main(String[] args) throws InterruptedException {
MyBlockingQueue<Integer> queue = new MyBlockingQueue<>(1);
for (int i = 0; i < 10; i++) {
int data = i;
new Thread(() -> {
try {
queue.enqueue(data);
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
System.out.println("1111111");
for(int i=0;i<10;i++){
new Thread(() -> {
try {
queue.dequeue();
}catch (InterruptedException e){
e.printStackTrace();
}
}).start();
}
}
public static class MyBlockingQueue<E> {
int size;//
ReentrantLock lock = new ReentrantLock(true);
LinkedList<E> list=new LinkedList<>();//
Condition notFull = lock.newCondition();//
Condition notEmpty = lock.newCondition();//
public MyBlockingQueue(int size) {
this.size = size;
}
public void enqueue(E e) throws InterruptedException {
lock.lock();
try {
while(list.size() ==size)// , notFull
notFull.await();
list.add(e);// :
System.out.println(" :" +e);
notEmpty.signal(); // notEmpty
} finally {
lock.unlock();
}
}
public E dequeue() throws InterruptedException {
E e;
lock.lock();
try {
while(list.size() == 0)
notEmpty.await();
e = list.removeFirst();// :
System.out.println(" :"+e);
notFull.signal();// notFull
return e;
} finally {
lock.unlock();
}
}
}
}
주 함수 가 20 개의 스 레 드 를 시 작 했 습 니 다.앞의 10 개 는 입대 한 후 10 개 는 팀 에서 나 왔 습 니 다.우 리 는 출력 결 과 를 볼 수 있 습 니 다.
new Thread(() -> {
try {
queue.enqueue(data);
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
스 레 드 구현 에 주의 하 십시오.이것 은 lambda 표현 식 이 Runable 인 터 페 이 스 를 실현 하 는 것 입 니 다.
:0
:0
:2
:2
:1
:1
:3
:3
:4
:4
:5
:5
:6
:6
:7
:7
:8
:8
:9
:9
1111111 이 첫 번 째 로 팀 을 나 가기 전에 대열 의 용량 이 1 인 것 을 볼 수 있다.즉,첫 10 개의 입단 과정 은 첫 번 째 성공 만 있 고 다른 것 은 모두 막 혔 다.그리고 팀 에 들 어 가 는 순 서 는 순환 순서에 따라 자 물 쇠 를 요청 순서에 따라 얻 는 것 을 설명 합 니 다.선착순 입 니 다.이것 은 바로 공평 자물쇠 라 는 뜻 입 니 다.사실 ReentrantLock 은 공평 자물쇠 일 수도 있 고 불공평 자물쇠 일 수도 있 습 니 다.초기 화 할 때 구조 편지 에 true 를 넣 으 면 공평 자물쇠 이 고 false 는 불공평 자물쇠 입 니 다.
재 입 자물쇠 가 무엇 인지 에 대해 서 는 이 편 을 볼 수 있 습 니 다https://www.jb51.net/article/175192.htm이것 은 재 입 자물쇠 의 인 스 턴 스 입 니 다.
그 중 한 줄 의 코드 가 이상 하 다.lock.lock();저 같은 몽 신 에 게 이 코드 가 무슨 일이 일 어 났 는 지 궁금 합 니 다.인터넷 에서 자 물 쇠 를 얻 었 다 고 하 는 경우 가 많 지만'얻 었 다'는 것 은 구체 적 이지 않 습 니 다.그래서 제 가 상상 해 봤 는데 대체적으로 이런 그림 인 것 같 습 니 다.
제 얕 은 경험 을 통 해 알 수 있 듯 이 jvm 은 하나의 준비 대기 열 만 있 습 니 다.준비 대기 열 안의 스 레 드 는 대기 열 순서에 따라 cpu 자원 을 사용 합 니 다.잠 금 을 넣 지 않 으 면 모든 스 레 드 는 순서대로 자원 을 얻 을 수 있 습 니 다.그러나 대상 을 대상 으로 하기 때문에 준비 대기 열 안의 스 레 드 의 입 대 순 서 를 직접 제어 할 수 없습니다.이 럴 때 는 스 레 드 의 운행 순 서 를 제어 하여 처리 논리 가 정확 하도록 해 야 한다.
코드 의 lock()방법 을 결합 하여 cpu 에 스 레 드 가 들 어 오고 lock()을 호출 합 니 다.이 잠 금 이 다른 스 레 드 에 의 해 가 져 오지 않 았 다 면 이 스 레 드 는 cpu 시간 을 사용 할 수 있 습 니 다.이 잠 금 이 다른 스 레 드 에 의 해 가 져 왔 다 면 이 스 레 드 는 차단 되 고 차단 대기 열 에 들 어 갈 것 입 니 다.이렇게 말 하면'가 져 오기'라 는 단어 도 이해 하기 어 려 운 것 이 없습니다.사실은 표시 일 뿐 입 니 다.그리고 lock()방법 은 현재 스 레 드 가 cpu 시간 을 사용 하 는 지,아니면 차단 대기 열 에 들 어 가 는 지 판단 하 는 것 일 뿐 입 니 다.
unlock()방법 을 보고 위의 그림 에서 도움 을 주 었 습 니 다.사실 이것 도 이해 하기 쉽 습 니 다.사실은 대기 열 을 막 는 팀 의 첫 번 째 스 레 드 를 팀 에서 내 고 준 비 된 대기 열 에 들 어 가 는 것 입 니 다.
실행 과정 에서 여러 개의 잠 금 인 스 턴 스 가 있 으 면 몇 개의 차단 가능 한 스 레 드 가 있 을 지 추측 할 수 있 습 니 다.그러면 여러 개의 잠 금 을 사용 하 는 것 외 에 다른 방법 으로 차단 스 레 드 를 증가 하 는 것 이 있 습 니 다.Condition 류 를 사용 하 는 것 입 니 다.condition 류 의 await()방법 을 지적 하면 현재 스 레 드 를 막 은 다음 에 현재 스 레 드 에서 얻 은 잠 금(특히 중요 한 점)을 자동 으로 해제 하고 스 레 드 를 전환 합 니 다.다른 스 레 드 에서 깨 어 나 면 이 스 레 드 는 깨 어 난 후에 스 레 드 가 await()의 위치 에서 계속 아래로 실 행 됩 니 다.따라서 일반적으로 while 순환 에 맞 춰 사용 해 야 합 니 다.만약 에 특정한 스 레 드 가 깨 어 나 면 그 전에 가 져 온 자물쇠 도 다시 가 져 옵 니 다.이때 이 자 물 쇠 는 다른 스 레 드 에 의 해 가 져 왔 고 잠 금 이 풀 리 지 않 았 으 면 깨 우 는 중 오류 가 발생 합 니 다.알 수 없 는 오류 가 발생 할 수 있 으 므 로 volatile 변 수 를 설정 하여 스 레 드 의 운행 상 태 를 검사 해 야 하기 때문에 await()방법 은 앞 뒤로 검 측 해 야 합 니 다.
여기 서 문 제 를 제기 합 니 다.leetcode 에서 왔 습 니 다.condition 류 를 사용 하여 쓰 라 고 요구 합 니 다.
제목:
1 부터 n 까지 이 숫자 를 나타 내 는 문자열 을 출력 할 수 있 는 프로그램 을 만 듭 니 다.하지만:
이 숫자 가 3 으로 나 눌 수 있다 면'fizz'를 출력 합 니 다.
이 숫자 가 5 로 나 눌 수 있다 면'버 즈'를 출력 합 니 다.
이 숫자 가 3 과 5 로 동시에 나 눌 수 있다 면'fizzbuzz'를 출력 합 니 다.
예 를 들 어 n=15,출력:1,2,fizz,4,buzz,fizz,7,8,fizz,buzz,11,fizz,13,14,fizzbuzz.
해법:
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Main {
static void printFizz(int x){
System.out.printf("%d:Fizz,
",x);
}
static void printBuzz(int x){
System.out.printf("%d:Buzz,
",x);
}
static void printFizzBuzz(int x){
System.out.printf("%d:FizzBuzz,
",x);
}
static void printaccpt(int x){
System.out.printf("%d,
",x);
}
static volatile int now=1;
static ReentrantLock lock=new ReentrantLock();
static Condition k1=lock.newCondition();
public static void test(int n) {
new Thread(()->{
while(now<=n){
lock.lock();
try{
while(now%5==0||now%3!=0){
if(now>n) throw new InterruptedException();
k1.await();
if(now>n) throw new InterruptedException();
}
printFizz(now);
now++;
k1.signalAll();
} catch (InterruptedException e) {
break;
//e.printStackTrace();
} finally{
lock.unlock();
}
}
System.out.println("Thread 1 is over");
}).start();
new Thread(()->{
while(now<=n){
lock.lock();
try{
while(now%5!=0||now%3==0) {
if(now>n) throw new InterruptedException();
k1.await();
if(now>n) throw new InterruptedException();
}
printBuzz(now);
now++;
k1.signalAll();
} catch (InterruptedException e) {
break;
// e.printStackTrace();
} finally{
lock.unlock();
}
}
System.out.println("Thread 2 is over");
}).start();
new Thread(()->{
while(now<=n){
lock.lock();
try{
while(now%5!=0||now%3!=0) {
if(now>n) throw new InterruptedException();
k1.await();
if(now>n) throw new InterruptedException();
}
printFizzBuzz(now);
now++;
k1.signalAll();
} catch (InterruptedException e) {
break;
//Thread.interrupted();
//e.printStackTrace();
} finally{
lock.unlock();
}
}
System.out.println("Thread 3 is over");
}).start();
new Thread(()->{
while(now<=n){
lock.lock();
try{
while(now%5==0||now%3==0) {
if(now>n) throw new InterruptedException();
k1.await();
if(now>n) throw new InterruptedException();
}
printaccpt(now);
now++;
k1.signalAll();
}catch (InterruptedException e){
break;
//Thread.interrupted();
//e.printStackTrace();
}
finally{
lock.unlock();
}
}
System.out.println("Thread 4 is over");
}).start();
}
public static void main(String[] args) throws InterruptedException {
test(30);
}
}
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Is Eclipse IDE dying?In 2014 the Eclipse IDE is the leading development environment for Java with a market share of approximately 65%. but ac...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.