동시 다발 에 관 한 간단 한 면접 문제
생각 나 는 방안 1:
public class Demo1 {
public static void main(String[] args) {
List integers = new ArrayList<>(10);
new Thread(() -> {
for (int i=0;i<10;i++) {
integers.add(i);
System.out.println("thread1 -> current integers size = " + integers.size());
}
}).start();
new Thread(()->{
while (true){
if (5 == integers.size()){
break;
}
}
System.out.println("thread2 -> integers size equals to 5");
}).start();
}
}
그러나 이 방안 은 옳지 않다
이유: 위의 코드 에서 두 스 레 드 의 list 는 같은 list 가 아 닙 니 다.이것 은 모든 스 레 드 가 생 성 될 때 각 스 레 드 내부 메모리 공간 에서 integers 집합 현재 상태의 복사 본 을 생 성 하기 때 문 입 니 다.따라서 스 레 드 1 이 integers 를 조작 할 때 스 레 드 2 가 보이 지 않 고 스 레 드 2 가 영원히 integers 의 초기 상태 이기 때문에 스 레 드 2 는 하나의 whiel (true) 순환 을 합 니 다.
프로젝트 1 수정: integers 를 구성원 변수 로 바 꾸 고 volatile 키 워드 를 추가 합 니 다.
public class Demo1 {
private volatile static List integers = new ArrayList<>(10);
public static void main(String[] args) throws Exception{
new Thread(() -> {
for (int i = 0; i < 10; i++) {
integers.add(i);
System.out.println("thread1 -> current integers size = " + integers.size());
}
}).start();
new Thread(() -> {
while (true) {
if (5 == integers.size()) {
break;
}
}
System.out.println("thread2 -> integers size equals to 5");
}).start();
}
}
이때 스 레 드 2 는 integers 요소 의 변 화 를 감지 할 수 있 습 니 다. 이것 은 volatile 키워드 의 가시 적 제약 때 문 입 니 다. 스 레 드 1 대 integers 의 수정 은 메 인 저장 소 에 있 는 integers 에 즉시 반응 하고 스 레 드 2 는 integers 변 수 를 사용 해 야 할 때 스 레 드 2 가 메 인 저장 소 에 있 는 integers 가 가리 키 는 대상 에 접근 하도록 강제 합 니 다.그래서 이때 스 레 드 2 는 integers 중의 요소 변 화 를 모니터링 할 수 있다.
여기 서 선 volatile 키워드 의 의 미 를 소개 해 야 합 니 다. volatile 의 한 역할 은 모든 스 레 드 가 volatile 에 의 해 수 정 된 변 수 를 방문 할 때 바로 메 인 저장 소 에 기록 하 는 것 입 니 다. 다른 스 레 드 는 volatile 에 의 해 수 정 된 변 수 를 읽 을 때 메 인 저장 소 에서 다시 읽 어야 합 니 다. 그러면 다른 스 레 드 (스 레 드 2) 를 보장 합 니 다.방문 한 integers 변 수 는 메 인 메모리 의 최신 입 니 다.
그래서 수 정 된 코드 도 완벽 하지 않다.
이 유 는 위 에서 말 한 스 레 드 2 가 메 인 메모리 의 최신 에 만 접근 할 수 있 기 때 문 입 니 다. 스 레 드 2 가 메 인 메모리 의 최신 integers 에 접근 한 후에 integers 변 수 를 판단 하기 전에 스 레 드 1 은 integers 에 요 소 를 추가 하 는 것 을 다시 완 료 했 고 스 레 드 2 는 최신 메 인 메모리 데이터 에 접근 하여 스 레 드 2 코드 만 계속 실행 할 것 입 니 다.메 인 저장 소 에 있 는 데 이 터 를 다시 방문 하지 않 습 니 다. 이 로 인해 스 레 드 2 가 integers 가 6 개 요소 일 때 만 integers 요소 가 5 개 라 는 힌트 를 보 냅 니 다.
프로젝트 1 수 정 된 수정: 자물쇠 사용
정확 해 보 이 는 코드
코드 논리: 스 레 드 1 이 integers 를 수정 한 이상 스 레 드 1 은 최신 integers 상 태 를 알 수 있 습 니 다. 스 레 드 2 는 integers 요소 의 수량 이 5 가 아 닐 때 lock 잠 금 으로 기다 리 고 스 레 드 1 은 실행 과정 에서 integers 요소 의 개 수 를 판단 하 며 5 이면 lock 을 잠 금 으로 하 는 스 레 드 를 깨 웁 니 다.
public class Demo1_2 {
public static void main(String[] args) throws Exception {
List integers = new ArrayList<>(10);
final Object lock = new Object();
new Thread(() -> {
synchronized (lock) {
for (int i = 0; i < 10; i++) {
integers.add(i);
if (5 == integers.size()) {
lock.notify();
}
System.out.println("thread1 -> current integers size = " + integers.size());
}
}
}).start();
new Thread(() -> {
if (5 != integers.size()) {
synchronized (lock) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
System.out.println("thread2 -> integers size equals to 5");
}).start();
}
}
코드 가 정확 하지 않 은 이 유 는 스 레 드 1 에서 lock 을 잠 금 으로 실행 하 는 코드 가 for 순환 이기 때문에 integers 요소 가 5 일 때 깨 어 났 지만 스 레 드 1 은 for 순환 이 끝 날 때 까지 lock 자 물 쇠 를 차지 하기 때문에 스 레 드 2 는 자 물 쇠 를 얻 을 수 없습니다. 라인 1 이 완전히 끝 난 후에 스 레 드 2 는 lock 자 물 쇠 를 얻 을 수 있 습 니 다.수정 방법 은 간단 합 니 다. 스 레 드 1 의 synchronized (lock) 를 if 판단 에 넣 고 진행 하면 됩 니 다.
메모: 스 레 드 1 이 integers 를 5 개 요소 에 추가 하여 lock. notify () 를 진행 할 수 있 습 니 다. 그러나 스 레 드 2 가 실행 되 지 않 아 스 레 드 2 가 실 행 될 때 wait 가 깨 어 나 지 않 아 프로그램 이 정상적으로 끝 날 수 없습니다.이 문제 의 수정 은 스 레 드 1 에서 수면 을 취하 고 스 레 드 2 를 먼저 실행 하도록 강제 하 는 것 이다.
또 하나의 자물쇠 없 는 실현 방식 이 있다.
CountDownlatch 사용 하기
public class Demo1_4 {
public static void main(String[] args) throws Exception {
List integers = new ArrayList<>(10);
CountDownLatch latch = new CountDownLatch(1);
new Thread(() -> {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i < 10; i++) {
integers.add(i);
if (5 == integers.size()) {
latch.countDown();
}
System.out.println("thread1 -> current integers size = " + integers.size());
}
}).start();
new Thread(() -> {
if (5 != integers.size()) {
try {
latch.await();
System.out.println("thread2 -> integers size equals to 5");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
요구 향상: 스 레 드 2 알림 이 완 료 된 후에 스 레 드 1 은 요 소 를 계속 추가 할 수 있 습 니 다.
이중 wait 와 notify 를 사용 하여 스 레 드 1 에서 integers 요소 의 수량 이 5 일 때 스 레 드 2 를 깨 우 고 자신 이 lock. wait () 자 물 쇠 를 풀 어 스 레 드 2 가 자 물 쇠 를 얻 을 수 있 도록 합 니 다. 스 레 드 2 가 실 행 된 후에 스 레 드 2 가 스 레 드 1 을 깨 우 고 스 레 드 2 알림 이 완 료 된 후에 라인 1 이 계속 실행 되 는 기능 을 실현 합 니 다.
public class Demo1_3 {
public static void main(String[] args) throws Exception {
List integers = new ArrayList<>(10);
final Object lock = new Object();
new Thread(() -> {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock) {
for (int i = 0; i < 10; i++) {
integers.add(i);
if (5 == integers.size()) {
lock.notify();
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("thread1 -> current integers size = " + integers.size());
}
}
}).start();
new Thread(() -> {
if (5 != integers.size()) {
synchronized (lock) {
try {
lock.wait();
System.out.println("thread2 -> integers size equals to 5");
lock.notify();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}
미 완성 계속...
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 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에 따라 라이센스가 부여됩니다.