실제로 주제는 광범위하지만 기본 사항을 설명하려고합니다. 자세한 내용은 다양한 blogs 및 기사에서 읽을 수 있습니다. 그 중 하나는 Java trail입니다.
경주에서 서로 나란히 실행되는 주자 (실제 인물) 인 것으로 각 스레드를 보는 것이 가장 좋습니다. 각 러너는 실행 중에 모든 작업을 수행 할 수 있습니다. 예를 들어 경주에서 주어진 순간에 테이블에서 물 한 컵을 가져옵니다. 육체적으로, 그들은 한꺼번에 같은 컵에서 마실 수는 없지만 가상 세계에서는 가능합니다 (라인이 그려지는 곳입니다).
예를 들어 두 명의 주자를 다시 가져옵니다. 그것들 각각은 트랙을 앞뒤로 움직여야하고, 각 끝에서 1'000'000 번 동안 버튼을 누르십시오 (주자가 공유 함). 버튼은 매번 카운터를 하나씩 증가시킵니다. 그들이 뛰기를 마쳤을 때 카운터의 가치는 무엇입니까? 육체적 인 세계에서 주자가 동시에 버튼을 밀 수 없기 때문에 2 천 파운드가 될 것입니다. 첫번째 선수가 떠나기를 기다릴 것입니다. 이것은 정확히 두 스레드가 할 것입니다.이 코드를 고려 :
public class ThreadTest extends Thread {
static public final int TOTAL_INC = 1000000;
static public int counter = 0;
@Override
public void run() {
for (int i=0; i<TOTAL_INC; i++) {
counter++;
}
System.out.println("Thread stopped incrementing counter " + TOTAL_INC + " times");
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new ThreadTest();
Thread t2 = new ThreadTest();
t1.start();
t2.start();
t1.join(); // wait for each thread to stop on their own...
t2.join(); //
System.out.println("Final counter is : " + counter + " which should be equal to " + TOTAL_INC * 2);
}
}
출력이 할 수있는 일 일단
Thread stopped incrementing counter 1000000 times
Thread stopped incrementing counter 1000000 times
Final counter is : 1143470 which should be equal to 2000000
동안의
등을 단지 두 번 같은 값을 증가 할 두 개의 스레드; 이것을 경쟁 조건이라고합니다.
동기화는 run
메서드가 작동하지 않으므로 잠금 메커니즘을 사용하여 이러한 일이 발생하지 않도록해야합니다. run
방법을 다음과 같이 변경을 고려
static private Object lock = new Object();
@Override
public void run() {
for (int i=0; i<TOTAL_INC; i++) {
synchronized(lock) {
counter++;
}
}
System.out.println("Thread stopped incrementing counter " + TOTAL_INC + " times");
}
지금 예상 출력이 우리가 공유 객체와 카운터를 동기화 한
...
Final counter is : 2000000 which should be equal to 2000000
입니다. 이는 단 한 명의 주자가 한 번에 버튼에 액세스 할 수 있기 전에 대기 행렬을 배치하는 것과 같습니다.
참고 :이 잠금 메커니즘은 mutex이라고합니다. 한 번에 n 스레드로 리소스에 액세스 할 수있는 경우 semaphore을 사용하는 것이 좋습니다.
멀티 스레딩은 교착 상태와 관련이 있습니다. A deadlock은 두 스레드가 동기화 된 자원을 계속 사용 가능하게하기 위해 다른 스레드가 상호 대기 할 때입니다. 예를 들어
- 스레드 1 시작
- 스레드 2 시작
- 스레드 1 개 취득 동기화 오브젝트 1
- 스레드 2 취득 동기화 object2
- 스레드 나사 (1)에 의해 로크 (계속하는 object2 획득 2 개 필요)
- 스레드 1이 스레드 2에 의해 잠기기 위해 계속하려면 object1을 획득해야합니다 (스레드 2에 의해 잠김)
- 프로그램이 교착 상태가됩니다.
이 문제가 발생하지 않도록하는 방법은 다양합니다 (스레드가 수행하는 작업과 구현 방법에 따라 달라질 수 있습니다 ...) 특히 그것에 대해 읽어야합니다.
참고 : 객체가 동기화 될 때 wait
, notify
및 notifyAll
만 호출 할 수있는 방법. 두 스레드가 동기화 블록 내에서 for...loop
블록을 실행하는
static public final int TOTAL_INC = 10;
static private int counter = 0;
static private Object lock = new Object();
static class Thread1 extends Thread {
@Override
public void run() {
synchronized (lock) {
for (int i=0; i<TOTAL_INC; i++) {
try {
lock.wait();
counter++;
lock.notify();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
static class Thread2 extends Thread {
@Override
public void run() {
synchronized (lock) {
for (int i=0; i<TOTAL_INC; i++) {
try {
lock.notify();
counter--;
lock.wait();
} catch (InterruptedException e) {
/* ignored */
}
}
}
}
}
공지 예를 들면 다음과 같습니다. 두 스레드가 모두 끝나면 counter == 0
의 결과입니다.이 작업은 리소스의 wait
및 notify
메서드를 통해 동기화 된 리소스에 "서로 허용"하기 때문에 수행 할 수 있습니다. 이 두 가지 방법을 사용하지 않으면 두 스레드가 순차적으로 동시에 실행되지 않고 (더 정확하게는 교대로) 실행됩니다.
이 내용이 스레드에 대해 (Java에서) 밝혀지기를 바랍니다.여기 **
** UPDATE가 Thilo 이전에 의해 제안 된 CountDownLatch 클래스 사용하여 위에서 설명한 모든 것의 개념의 작은 증거입니다 : 자바 개념이 아니다
static class Server {
static public final int NODE_COUNT = 5;
private List<RunnableNode> nodes;
private CountDownLatch startSignal;
private Object lock = new Object();
public Server() {
nodes = Collections.synchronizedList(new ArrayList<RunnableNode>());
startSignal = new CountDownLatch(Server.NODE_COUNT);
}
public Object getLock() {
return lock;
}
public synchronized void connect(RunnableNode node) {
if (startSignal.getCount() > 0) {
startSignal.countDown();
nodes.add(node);
System.out.println("Received connection from node " + node.getId() + " (" + startSignal.getCount() + " remaining...)");
} else {
System.out.println("Client overflow! Refusing connection from node " + node.getId());
throw new IllegalStateException("Too many nodes connected");
}
}
public void shutdown() {
for (RunnableNode node : nodes) {
node.shutdown();
}
}
public void awaitAllConnections() {
try {
startSignal.await();
synchronized (lock) {
lock.notifyAll(); // awake all nodes
}
} catch (InterruptedException e) {
/* ignore */
shutdown(); // properly close any connected node now
}
}
}
static class RunnableNode implements Runnable {
private Server server;
private int id;
private boolean working;
public RunnableNode(int id, Server server) {
this.id = id;
this.server = server;
this.working = true;
}
public int getId() {
return id;
}
public void run() {
try {
Thread.sleep((long) (Math.random() * 5) * 1000); // just wait randomly from 0 to 5 seconds....
synchronized (server.getLock()) {
server.connect(this);
server.getLock().wait();
}
if (!Thread.currentThread().isAlive()) {
throw new InterruptedException();
} else {
System.out.println("Node " + id + " started successfully!");
while (working) {
Thread.yield();
}
}
} catch (InterruptedException e1) {
System.out.print("Ooop! ...");
} catch (IllegalStateException e2) {
System.out.print("Awwww! Too late! ...");
}
System.out.println("Node " + id + " is shutting down");
}
public void shutdown() {
working = false; // shutdown node here...
}
}
static public void main(String...args) throws InterruptedException {
Server server = new Server();
for (int i=0; i<Server.NODE_COUNT + 4; i++) { // create 4 more nodes than needed...
new Thread(new RunnableNode(i, server)).start();
}
server.awaitAllConnections();
System.out.println("All connection received! Server started!");
Thread.sleep(6000);
server.shutdown();
}
멀티 스레딩을, 그것을 많은 프로그래밍 언어에 존재합니다. Java는 내 의견으로는 아마도 가장 쉬운 방법 중 하나 일 것입니다. (스레드) –