클래스 [X] (및 해당 오브젝트 [xObject])가 있고 정수 2 개 [A]와 [B]가 있다고 가정하십시오. 하나는 [A]를 수정하고 다른 하나는 [B]를 수정하는 두 개의 스레드가 있습니다. 두 스레드가 [xObject]의 값을 변경하기 때문에 서로 다른 메모리 위치 (실제로)가 있으므로 [xObject] 또는 [A]와 [B]에 대한 액세스를 동기화해야합니까? 그리고 어디에서이 FALL 끝나는 것처럼, 내가 배열의 두 개의 다른 위치에 동시에 액세스해야합니까 또는 arrayList 안에?오브젝트 내부에서 동기화, 오브젝트 또는 데이터가 정확히 필요합니까?
답변
두 개의 독립적 인 int
속성이있는 경우 전혀 동기화 할 필요가 없습니다. 동기화하는 유일한 이유는 두 개 이상의 메모리 위치가 관련되어있을 때 일관성을 유지하기 위해서입니다. 독립적 인 위치가있는 경우 volatile
은 변경 사항에 대한 스레드 간 가시성을 보장하기에 충분합니다.
예를 들어, int
속성이 독립적이지 않은 경우 동기화해야합니다. 하나의 속성이 현재 값을 나타내고 다른 속성이 최대 값을 나타냅니다. max보다 큰 현재 값을 설정하면 예외가 발생합니다. 현재 값보다 큰 최대 값을 설정하면 현재 값이 새로운 최대 값으로 변경됩니다. 배열과 모음에 대한
public class Test {
int current = 10;
int max = 100;
public synchronized int getMax() { return max; }
public synchronized int getCurrent() { return max; }
public synchronized void setCurrent(int c) {
if (c > max) throw new IllegalStateException();
current = c;
}
public synchronized void setMax(int m) {
max = m;
if (current > m) current = m;
}
}
결정은 더 복잡하다 : 당신 액세스 배열 요소지만, 배열 자체가 고정 된 상태를 유지하고, 배열 요소가 독립적 인 경우에, 당신은 동기화를 건너 뛸 수 있습니다. 그러나 요소가 독립적이지 않거나 컬렉션이 더 복잡한 경우 (예 : 배열 목록 또는 해시 테이블) 동기화 작업이 필요합니다. 컬렉션 작업이 컬렉션을 구조적으로 변경하여 일관성을 잃을 수 있기 때문입니다.
배열에 대해 무슨 뜻인지 확실하지 않지만 두 개의 서로 다른 값을 변경하고 다른 스레드에서 값을 읽지 않으면 동기화 할 필요가 없습니다. 당신이 클래스 X.
또는 사용에 같은 휘발성하지 않는 한 당신이 스레드 1 변수 xObject.a의 값을 변경하고 실 2 3 다음 오래된 얻을 수있는 몇 가지 다른 스레드를 읽고 있다면
읽기 java.util.concurrent 패키지의 동기화 유틸리티 중 하나. 구글 주위에 또는 stackoverflow 예를 들어 검색 할 수 있습니다.
클라이언트가 볼 수없는 중간 상태에 따라 다릅니다. 객체에 허용되지 않은 (A)의 조합 B가있는 경우
는 예를 들어, 당신은 모두가 액세스를 통해 동기화해야합니다 :
class Person {
private final Object _lock = new Object(); // for synchronization
private int _age;
private boolean _married;
public void setAge(int age) {
if (age <= 0) throw new IllegalArgumentException();
synchronized(_lock) {
// age < 18 implies !married
_age = age;
if (age < 18) married = false;
}
}
}
당신이 작업을 수행 할 수 있습니다 경우에도 A와 B 서로 독립적 인 :
class ComplexNumber {
private final Object _lockRe = new Object();
private final Object _lockIm = new Object();
private int _re, _im;
...
public void setValue(int re, int im) {
synchronized(_lockRe) { _re = re; }
synchronized(_lockIm) { _im = im; }
}
}
당신이 다음
ComplexNumber c = new ComplexNumber(0, 0);
c.setValue(1, 2);
일한다면 read는 설정되지 않은 (1,0)을 볼 수 있습니다. 이것은 응용 프로그램에 따라 허용 될 수도 있고 허용되지 않을 수도 있습니다.
클래스가 멀티 스레드 환경에서 사용되는 경우 getter 또는 공용 액세스를 사용하여 사용 가능한 모든 데이터를 잠그는 것이 좋습니다.
그런 식으로 특정 규칙 ("B에 액세스하는 경우 A를 수정해서는 안 됨)"을 알거나 고려하기 위해 사용자 (클래스를 API로 사용하는 코드)를 강요하지 않습니다.어떤 데이터 항목을 동기화해야하는지에 대해 신경 쓰지 않고 즉시 사용할 수있는 방법을 사용할 수 있습니다. 또한 적은 설명서;)