다중 스레드 Thread 클래스와 Runnable 인터페이스 자원 공유 문제 분석
7817 단어 java 병렬 및 다중 루틴
public class TicketSaleMain implements Runnable{
private int num = 5; // 5
public void run() {
System.out.println(Thread.currentThread().getName() );//
for(int i=0; i<10; i++){
if(this.num>0){ //
System.out.println(Thread.currentThread().getName() + " : " + this.num--);
}
}
}
public static void main(String[] args) {
TicketSaleMain ticketThread = new TicketSaleMain(); // Runnable A
Thread th1 = new Thread(ticketThread); // A
th1.setName(" ");
Thread th2 = new Thread(ticketThread); // A
th2.setName(" ");
Thread th3 = new Thread(ticketThread); // A
th3.setName(" ");
th1.start();
th2.start();
th3.start();
}
}
실행 결과:
: 5
: 4
: 3
: 2
: 1
Ticket Sale Main이 선언한 더미에 놓인 대상인 ticket Thread 3개의 스레드가 모두 이 대상을 가리키기 때문에 구성원 속성num=5를 자연스럽게 공유했다. 이는 한 임무를 3개 스레드에 끼워 넣는 것과 같다. 매표 임무는 3개 스레드가 공동으로 수행할 수 있기 때문에 자원 공유에 도달할 수 있다. 그러나 상술한 결과는 항상 같은 순서로 줄어드는 것이 아니다. 이런 결과가 있을 것이다. 운행 결과 1:
: 5
: 3
: 2
: 1
: 4
이것은 병발이 그렇기 때문이다. 만약 당신이 병발 제어를 하지 않는다면, 각종 기이한 현상이 발생할 것이다. 왜냐하면 라인 집행은 교차 집행이기 때문이다.즉, 창 1과 창 2는 각각 선후로this를 실행한다.num – 이후 창에서 println을 실행했지만, 창 2가 지나서야 println을 실행했습니다.2: 실행 결과 2:
: 5
: 5
: 4
: 2
: 3
: 1
창 1과 창 2가 각각this를 동시에 실행합니다.num – 이후에 println을 함께 실행하면 이런 상황은 여러 번 실행해야만 한 번 나타난다. 더욱 뚜렷하게 하려면run 방법을 다음과 같이 수정할 수 있다.
public void run() {
System.out.println(Thread.currentThread().getName() );//
for(int i=0; i<10; i++){
try {
Thread.sleep(1000); // 1000ms
}
catch (InterruptedException e) {
e.printStackTrace();
}
if(this.num>0){ //
System.out.println(Thread.currentThread().getName() + " : " + this.num--);
}
}
}
실행 결과:
: 5
: 4
: 3
: 2
: 1
: 1
상술한 상황은 모두 다중 스레드에 대한 병렬 제어가 없기 때문에 스레드에 대해 동기화 작업을 해야 한다. 스레드가 자원 경쟁에 대한 문제를 피하고 스레드 안전 문제가 발생하는 것을 방지해야 한다. 동기화 작업은 같은 시간대에 한 스레드만 진행할 수 있다
System.out.println(Thread.currentThread().getName() + " : " + this.num--);
. 그 나머지 스레드는 이 스레드가 완성된 후에야 계속 집행할 수 있다.여기서synchronized 키워드로 동기화합니다.synchronized 키워드는 동기화 방법도 있고 코드 블록도 동기화할 수 있습니다.
동기화 방법은 for 순환 내의 코드를 하나의 방법인 booking () 으로 봉하고,public synchronized void로 설명한 다음에run ()에서 booking 방법을 호출하는 것이다
동기화 코드 블록은synchronized(this) {} for 순환 후의 코드 블록을 패키지로 묶어서 동기화 제어를 할 수 있습니다.
그 다음에 Thread 클래스를 계승하여 다중 루틴을 실현한다. 여기서 더 이상 말하지 않고 바로 코드를 올린다.
public class TicketSaleMain extends Thread
private int num = 5; // 5
@Override
public void run() {
System.out.println(Thread.currentThread().getName() ); //
for(int i=0; i<10; i++){
if(this.num>0){ //
System.out.println(Thread.currentThread().getName() + " : " + this.num--);
}
}
}
public static void main(String[] args) {
TicketSaleMain th1 = new TicketSaleMain(); //
th1.setName(" ");
TicketSaleMain th2 = new TicketSaleMain(); //
th2.setName(" ");
TicketSaleMain th3 = new TicketSaleMain(); //
th3.setName(" "); //
th1.start();
th2.start();
th3.start();
}
}
실행 결과:
: 5
: 4
: 3
: 2
: 1
: 5
: 4
: 5
: 3
: 4
: 2
: 3
: 1
: 2
: 1
운행 결과를 보면 Thread류를 계승하여 다중 라인을 실현하려면 몇 개의 라인이 몇 개의 대상을 성명해야 한다. 각 대상은num=5를 귀속시켰다. 이는 매표 임무마다 한 라인을 귀속시키는 것과 같다. 각 라인이 수행하는 매표 임무는 같은 라인이 아니기 때문에 자원 공유를 실현하지 못했다.