Java 학습 노트 45(다중 스레드 2: 보안 문제 및 해결 원리)
여러 개의 스레드가 한 개의 공유 데이터를 사용할 때 안전 문제가 발생한다
대표적인 사례:
영화관 매표소 는 모두 100석, 최대 100장, 매표 방식 이 다양하다
세 가지 방식으로 같은 공유 데이터를 조작하면 안전 문제가 발생할 수 있다.
예:
package demo1;
public class Tickets implements Runnable {
private int ticket = 100;
public void run(){
while(true){
if (ticket>0) {
System.out.println(Thread.currentThread().getName()+" "+ticket--+" ");
}
}
}
}
package demo1;
public class ThreadDemo {
public static void main(String[] args) {
Tickets t = new Tickets();
Thread t0 = new Thread(t);
Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
t0.start();
t1.start();
t2.start();
}
}
일반적으로 문제가 생기지 않지만, 이런 문제를 생각해야 한다.
그러나 마지막 표만 남았다고 가정하면 한 라인이 CPU 자원 집행을 뺏는다. 판단이 끝날 때 CPU 자원은 다른 라인에 뺏기고 다른 라인이 판단하고 집행한다.
이때 시작할 때의 노선이 이미 판단이 끝났기 때문에 계속 집행하면 표 수가 마이너스로 변하기 때문에 여기에 문제가 생겼다
해결 방법:
동기화 코드 블록
원리: 한 라인이 데이터 조작에 들어갈 때 다른 라인의 집행을 막는다
package demo1;
public class Tickets implements Runnable {
private int ticket = 100;
private Object obj1 = new Object();
public void run() {
while (true) {
synchronized (obj1) {
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + " " + ticket-- + " ");
}
}
}
}
}
하지만 안전했지만 운행 속도가 떨어졌다
그러나 우리는 안전성을 위해 속도를 고려하지 않고 어쨌든 안전성을 확보해야 한다
여기에 전송된 대상 매개 변수는 약칭: 동기화 자물쇠, 전문 이름: 대상 모니터
원리:
자물쇠가 없는 라인은 실행할 수 없고 기다릴 수 있습니다
루틴이 동기화 코드 블록을 만났을 때 동기화 자물쇠가 있는지 판단합니다. 만약 있다면 자물쇠를 가져가서 동기화에 들어가서 실행하고 실행이 끝난 후에 자물쇠 대상을 돌려보냅니다.
다른 스레드가 코드 블록을 만났을 때 자물쇠가 없어서 들어갈 수 없습니다. 원래의 스레드가 자물쇠를 돌려준 후에 새로운 스레드가 자물쇠를 가져와 순환합니다
여기서 분명히 알 수 있듯이, 이렇게 많은 과정 에서 속도 는 자연히 느려졌다
동기화 방식으로 문제 해결:
장점: 낮은 코드 수
package demo1;
public class Tickets implements Runnable {
private int ticket = 100;
public void run() {
while (true) {
payTicket();
}
}
public synchronized void payTicket() {
// : this
// .class
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + " " + ticket-- + " ");
}
}
}
단점: 이상이 발생하면 방법의 자물쇠 대상이 방출되지 않고 동기화되지 않으며 자물쇠가 방출되지 않습니다
여기에는 Lock 인터페이스가 필요합니다.
더욱 광범위한 잠금 작업 제공
이전 티켓 판매 사례 개선:
package demo1;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Tickets implements Runnable {
private int ticket = 100;
private Lock lock = new ReentrantLock();
public void run() {
while (true) {
lock.lock();
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + " " + ticket-- + " ");
}
lock.unlock();
}
}
}
고정 자물쇠:
동기식 잠금으로 인한 폐단:
스레드 작업에 여러 개의 동기화가 생겼을 때 동기화에 다른 동기화가 끼워져 있으면 이때 일종의 현상을 일으키고 프로그램에 무한한 기다림이 나타난다. 이런 현상을 사쇄라고 부른다.
두 사람이 국수 한 그릇을 먹는데 젓가락이 한 켤레밖에 없다. 두 사람이 한 젓가락을 뺏으면 손으로 잡지 못하도록 규정되어 있다. 이때 국수를 먹을 수 없다.
코드 구현:
package demo1;
public class LockA {
private LockA(){}
public final static LockA locka =new LockA();
}
package demo1;
public class LockB {
private LockB(){}
public final static LockB lockb =new LockB();
}
package demo1;
public class DeadLock implements Runnable {
private int i = 0;
public void run() {
while (true) {
if (i % 2 == 0) {
synchronized (LockA.locka) {
System.out.println("if...locka");
synchronized (LockB.lockb) {
System.out.println("if...lockb");
}
}
} else {
synchronized (LockB.lockb) {
System.out.println("else...lockb");
synchronized (LockA.locka) {
System.out.println("else...locka");
}
}
}
i++;
}
}
}
package demo1;
public class DeadLockDemo {
public static void main(String[] args) {
DeadLock dead = new DeadLock();
Thread t0 = new Thread(dead);
Thread t1 = new Thread(dead);
t0.start();
t1.start();
}
}
운행 후 어느 곳에 끼어 움직이지 않지만 멈추지 않는 것을 발견하였다
전재 대상:https://www.cnblogs.com/xuyiqing/p/8320162.html
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.