1. 동기 문제가 발생했습니다
스레드 동기화는 여러 스레드가 데이터 객체에 액세스 할 때 데이터 손상을 방지하는 것입니다.
예를 들어, 2 스레드와 스레드는 동일한 FOO 객체를 작동하고 FOO 객체의 데이터를 수정합니다.
패키지 CN.thread; public class foo {private int x = 100; public int getx () {return x; } public int fix (int y) {x = x -y; 반환 x; }} 패키지 cn.thread; 공개 클래스 myrunnable emplements runnable {private foo foo = new foo (); public static void main (String [] args) {myrunnable run = new Myrunnable (); 스레드 ta = 새 스레드 (run, "stride-a"); 스레드 tb = 새 스레드 (run, "Thread-B"); ta.start (); tb.start (); } public void run () {for (int i = 0; i <3; i ++) {this.fix (30); try {thread.sleep (1); } catch (InterruptedException e) {e.printstacktrace (); } system.out.println (thread.currentthread (). getName () + ": 현재 foo 객체의 x 값 =" + foo.getx ()); }} public int fix (int y) {return foo.fix (y); }}실행 결과 :
스레드 B : 현재 foo 객체의 x 값 = 40
Thread-A : 현재 foo 객체의 x 값 = 40
스레드 B : 현재 foo 객체의 x 값 = -20
스레드 A : 현재 foo 객체의 x 값 = -20
스레드 B : 현재 foo 객체의 x 값 = -80
스레드 A : 현재 foo 객체의 x 값 = -80
결과로부터, 그러한 출력 값은 분명히 불합리한 것으로 밝혀졌다. 그 이유는 두 스레드가 제어없이 Foo 객체에 액세스하고 데이터를 수정하기 때문입니다.
결과의 합리성을 유지하려면 FOO에 대한 액세스를 제한하는 하나의 목표 만 달성하면 한 번에 한 번만 액세스 할 수 있습니다. 이것은 FOO 객체에서 데이터의 합리성을 보장합니다.
특정 Java 코드에서는 두 가지 작업을 완료해야합니다.
경쟁에서 방문한 리소스 클래스의 FOO 변수 X를 비공개로 식별하십시오.
변수를 수정하는 코드를 동기화하고 동기화 된 키워드를 사용하여 메소드 또는 코드를 동기화하십시오.
패키지 CN.thread; 공개 클래스 foo2 {private int x = 100; public int getx () {return x; } // 동기화 된 방법 public synchronized int fix (int y) {x = x -y; system.out.println ( "스레드" + 스레드. 반환 x; } // synchronized code block // public int fix (int y) {// synchronized (this) {// x = x -y; // system.out.out.println ( "스레드" + thread.currentThread (). getName () + "" " + y // +" "," " + y // +" " 패키지 cn.thread; public class myrunnable2 {public static void main (String [] args) {myrunnable2 run = new Myrunnable2 (); foo2 foo2 = 새로운 foo2 (); 신화 t1 = run.new mythread ( "스레드 a", foo2, 10); 신화 t2 = run.new mythread ( "스레드 B", foo2, -2); 신화 t3 = run.new mythread ( "스레드 c", foo2, -3); Mythread T4 = Run.New Mythread ( "스레드 D", Foo2, 5); t1.start (); t2.start (); t3.start (); t4.start (); } class mythread는 스레드 {private foo2 foo2; / ** 현재 값*/ private int y = 0; 신화 (문자열 이름, foo2 foo2, int y) {super (name); this.foo2 = foo2; this.y = y; } public void run () {foo2.fix (y); }}} 스레드 a 런 끝, "10"을 줄이고, 현재 값은 90입니다.
스레드 C는 실행 및 끝, "-3"을 줄이고 현재 값은 93입니다.
스레드 B는 끝에서 실행되고 "-2"를 줄이고 현재 값은 95입니다.
스레드 D가 실행되고 끝나고 "5"를 줄이고 현재 값은 90입니다.
2. 동기화 및 잠금
1. 자물쇠의 원리
Java의 각 객체에는 내장 잠금 장치가 있습니다.
프로그램이 비 정적 동기화 된 동기화 메소드에서 실행되면, 실행중인 코드 클래스의 현재 인스턴스와 관련된 잠금 장치 (이 인스턴스). 객체를 얻는 잠금 잠금 장치를 잠금, 객체 잠금, 물체를 잠그거나 객체를 동기화하는 것도라고도합니다.
객체 잠금은 프로그램이 동기화 된 동기화 방법 또는 코드 블록으로 실행될 때만 작동합니다.
물체에 대한 잠금은 단 하나뿐입니다. 따라서 스레드가 잠금을 획득하면 첫 번째 스레드가 잠금을 풀거나 리턴 할 때까지 다른 스레드가 잠금을 획득 할 수 없습니다. 또한 잠금이 해제 될 때까지 다른 스레드가 객체의 동기화 된 메소드 또는 코드 블록을 입력 할 수 없음을 의미합니다.
잠금을 해제한다는 것은 잠금 스레드가 동기화 된 동기화 방법 또는 코드 블록을 종료한다는 것을 의미합니다.
잠금 및 동기화에 대한 몇 가지 핵심 사항이 있습니다.
1) 방법 만 동기화 될 수 있지만 변수와 클래스는 동기화 될 수 없습니다.
2) 각 객체에는 하나의 잠금이 있습니다. 동기화와 관련하여 무엇을 명확하게해야합니까? 즉, 어떤 객체에 동기화됩니까?
3) 클래스의 모든 메소드를 동기화 할 필요가 없습니다. 클래스는 동기 및 비동기 방법을 모두 가질 수 있습니다.
4) 두 스레드가 한 클래스에서 동기화 된 메소드를 실행하고 두 스레드가 동일한 인스턴스를 사용하여 메소드를 호출하려면 한 번만 한 번만 메소드를 실행할 수 있으며 다른 스레드만이 잠금이 해제 될 때까지 대기해야합니다. 즉, 스레드가 객체의 잠금을 획득하는 경우 다른 스레드는 해당 객체의 클래스에서 동기화 메소드를 입력 할 수 없습니다.
5) 스레드에 동기화 및 비동기 방법이있는 경우, 잠금에 의해 제한되지 않고 비동기 방법에 여러 스레드에 의해 비동기 방법에 자유롭게 액세스 할 수 있습니다.
6) 스레드가 잠들 때 잠금 장치가 없어집니다.
7) 스레드는 여러 자물쇠를 얻을 수 있습니다. 예를 들어, 한 개체의 동기화 메소드에서 다른 객체의 동기화 방법을 호출하면 두 객체의 동기화 잠금이 획득됩니다.
8) 동기화는 동시성을 손상시키고 가능한 한 많이 동기화 범위를 좁 힙니다. 동기화는 전체 메소드를 동기화 할뿐만 아니라 메소드의 일부 코드 블록을 동기화 할 수 있습니다.
9) 동기화 코드 블록을 사용하는 경우 동기화 할 객체, 즉 객체의 잠금을 획득 할 객체를 지정해야합니다. 예를 들어:
public int fix (int y) {synchronized (this) {x = x -y; } return x;} 물론 동기화 방법을 비동기 방법으로 다시 작성할 수도 있지만 함수는 예를 들어 다음과 같습니다.
public synchronized int getx () {return x ++;} 그리고
public int getx () {synchronized (this) {return x ++; }}효과는 정확히 동일합니다.
3. 정적 메소드 동기화
정적 메소드를 동기화하려면이 클래스 (xxx.class) 인 전체 클래스 객체에 잠금이 필요합니다.
예를 들어:
public static synchronized int setname (문자열 이름) {xxx.name = name;}
동등합니다
public static int setname (문자열 이름) {synchronized (xxx.class) {xxx.name = name; }}4. 스레드가 잠금을 얻을 수 없다면 어떻게됩니까?
스레드가 동기 메소드를 입력하려고 시도하고 잠금이 점유되면 실이 객체에서 차단됩니다. 본질적으로, 실은 물체의 풀에 들어가고 잠금이 풀릴 때까지 기다려야하고 스레드가 실행 가능하거나 다시 실행 해야하는 곳을 기다려야합니다.
차단을 고려할 때 어떤 물체가 잠금에 사용되는지주의를 기울여야합니다.
1. 동일한 객체에서 비 정적 동기화 메소드를 호출하는 스레드는 서로를 차단합니다. 다른 객체 인 경우 각 스레드에는 자체 객체 잠금 장치가 있으며 스레드는 서로 방해하지 않습니다.
2. 동일한 클래스에서 정적 동기화 메소드를 호출하는 스레드는 서로를 차단하며 모두 동일한 클래스 객체에 잠겨 있습니다.
3. 정적 동기화 방법과 비 정적 동기화 방법은 정적 메소드가 클래스 객체에 고정되어 있고 비 정적 메소드 가이 클래스의 객체에 잠겨 있기 때문에 서로를 차단하지 않습니다.
4. 동기화 된 코드 블록의 경우 잠금에 사용 된 객체 (동기화 후 동기화 된 브래킷의 내용)를 명확하게 확인해야합니다. 동일한 객체에 동기화 된 스레드는 서로를 차단하고 다른 객체에 잠긴 스레드는 서로를 차단하지 않습니다.
5. 언제 동기화해야 할 필요가 있습니까?
여러 스레드가 상호 배타적으로 (교환 가능) 데이터에 동시에 액세스하면 데이터를 보호하기 위해 동기화되어 동시에 데이터를 수정하고 변경하지 않도록해야합니다.
비 정적 필드에서 변경할 수있는 데이터의 경우 일반적으로 비 정적 방법에 액세스합니다.
정적 필드에서 변경할 수있는 데이터의 경우 일반적으로 정적 방법을 사용하여 액세스합니다.
정적이 아닌 방법으로 정적 필드를 사용하거나 정적 필드에서 비 정적 메소드를 호출 해야하는 경우 문제가 매우 복잡해집니다. SJCP 시험의 범위를 초과했습니다.
6. 스레드 안전 범주
클래스가 데이터를 보호하기 위해 잘 동기화되면이 클래스를 "스레드-안전"이라고합니다.
스레드 안전 클래스의 경우에도 작동하는 스레드가 여전히 안전하지 않기 때문에 매우 조심해야합니다.
7. 스레드 동기화 요약
1. 스레드 동기화의 목적은 여러 스레드가 리소스에 액세스 할 때 리소스 손상을 보호하는 것입니다.
2. 스레드 동기화 방법은 잠금을 통해 구현됩니다. 각 객체에는 하나의 잠금 만 있습니다. 이 잠금은 특정 객체와 관련이 있습니다. 스레드가 객체 잠금을 획득하면 객체에 액세스하는 다른 스레드는 더 이상 객체의 다른 동기화 방법에 액세스 할 수 없습니다.
3. 정적 동기화 방법의 경우이 클래스의 잠금 장치이며 잠금 객체는이 클래스의 클래스 객체입니다. 정적 및 비 정적 방법의 잠금은 서로를 방해하지 않습니다. 스레드는 잠금을 획득하고 동기화 메소드의 다른 객체에서 동기화 메소드에 액세스 할 때이 두 객체 잠금을 얻습니다.
4. 동기화의 경우 항상 동기화 할 객체를 항상 알고 있어야합니다.
5. 스레드-안전 클래스를 작성할 때는 자원에 액세스하기 위해 경쟁하는 여러 스레드의 논리 및 보안에 대한 올바른 판단에 항상주의를 기울여야하며 "원자"작업을 분석하며 원자 운영 중에 다른 스레드가 경쟁 자원에 액세스 할 수 없도록해야합니다.
6. 여러 스레드가 객체 잠금을 기다리는 경우 잠금을 얻지 못한 스레드가 차단됩니다.
7. 교착 상태는 서로 잠금을 기다리는 실이 발생하며 실제로 발생할 확률은 매우 작습니다. 교착 상태 프로그램을 작성하고 싶다면 쉽지 않을 수 있습니다. 그러나 일단 프로그램이 사라지면 프로그램이 죽을 것입니다.
원본 링크 : http://www.cnblogs.com/linjiqin/p/320843.html
위는이 기사의 모든 내용입니다. 모든 사람의 학습에 도움이되기를 바랍니다. 모든 사람이 wulin.com을 더 지원하기를 바랍니다.