//★★Synchronized(동기화)
- 동기화된 메서드는 수많은 스레드 중 단 한 개의 스레드에서만 실행 가능 > thread safe
package com.sorrel012.com;
public class ConcurrencyRunner {
public static void main(String[] args) {
Counter counter = new Counter();
counter.increment();
counter.increment();
counter.increment();
System.out.println(counter.getI());
} //main
}
package com.sorrel012.com;
public class Counter {
private int i = 0;
public int getI() {
return i;
}
synchronized public void increment() {
i++;
}
}
- ★동기화는 overhead가 많이 생김.
> 다른 코드를 실행해야 하는 스레드들이 무조건 대기를 해야 되기 때문
package com.sorrel012.com;
public class BiCounter {
private int i = 0;
private int j = 0;
synchronized public void incrementI() {
i++;
}
public int getI() {
return i;
}
synchronized public void incrementJ() {
j++;
}
public int getJ() {
return j;
}
}
// Lock
- synchronized의 문제점을 해결하기 위해 사용한다.
- 하나의 동기화된 커다란 코드를 갖고 있는 것이 아니라 여러 개의 작은 코드로 쪼갬으로써 thread가 해당 코드를 수행하는 동안 병렬 구조를 통해 다른 thread 또한 코드를 실행할 수 있다. > 유연성
- import java.util.concurrent.locks.Lock;
- import java.util.concurrent.locks.ReentrantLock;
- 선언 및 생성
Lock 변수명 = new ReentrantLock();
- 변수명.lock() : lock을 호출할 때 해당 lock을 갖는 다른 thread가 존재하지 않는다면 lock을 얻고 작업을 수행한다.
- 변수명.unlock() : 작업을 수행한 후 lock을 release한다.
-변수명.trylock() : lock을 이곳 저곳에서 사용할 수 있게 해준다.
> lock을 사용하지 못하게 된다면, false 반환
package com.sorrel012.com;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class BiCounterWithLock {
private int i = 0;
private int j = 0;
Lock lockForI = new ReentrantLock();
Lock lockForJ = new ReentrantLock();
public void incrementI() {
lockForI.lock(); //Get Lock For I
i++;
lockForI.unlock(); //Release Lock For I
}
public int getI() {
return i;
}
public void incrementJ() {
lockForJ.lock(); //Get Lock For J
j++;
lockForJ.unlock(); //Release Lock For J
}
public int getJ() {
return j;
}
}
package com.sorrel012.com;
public class ConcurrencyRunner {
public static void main(String[] args) {
BiCounterWithLock lock = new BiCounterWithLock();
lock.incrementI();
lock.incrementI();
lock.incrementJ();
lock.incrementI();
System.out.println(lock.getI());
System.out.println(lock.getJ());
} //main
}
//AtomicInteger
- '자동 숫자 증가' 와 같은 응용 프로그램에서 lock 대신 간단하게 사용할 수 있다.
- import java.util.concurrent.atomic.AtomicInteger;
- 선언 및 생성
AtomicInteger 변수명 = new AtomicInteger();
- 변수명.incrementAndGet() : 숫자를 증가시켜준다.
- 변수명.decrementAndGet() : 숫자를 감소시켜준다.
- 변수명.Get() : 숫자를 반환한다.
package com.sorrel012.com;
import java.util.concurrent.atomic.AtomicInteger;
public class BiCounterWithAtomicInteger {
private AtomicInteger i = new AtomicInteger();
private AtomicInteger j = new AtomicInteger();
public void incrementI() {
i.incrementAndGet();
}
public void decrementI() {
i.decrementAndGet();
}
public int getI() {
return i.get();
}
public void incrementJ() {
j.incrementAndGet();
}
public int getJ() {
return j.get();
}
}
package com.sorrel012.com;
public class ConcurrencyRunner {
public static void main(String[] args) {
BiCounterWithAtomicInteger atomic = new BiCounterWithAtomicInteger();
atomic.incrementI();
atomic.incrementI();
atomic.incrementI();
System.out.println(atomic.getI());
atomic.decrementI();
System.out.println(atomic.getI());
} //main
}
// ConcurrentCollection
- 장황한 단계들을 거쳐야 하는 연산을 atomic 연산으로 변환해 준다.
- ConcurrentHashMap
package com.sorrel012.com;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.LongAdder;
public class ConcurrentMapRunner {
public static void main(String[] args) {
ConcurrentMap<Character, LongAdder> occurances = new ConcurrentHashMap<>();
String str = "ABCD ABCD ABCD";
for(char character:str.toCharArray()) {
occurances.computeIfAbsent(character, ch -> new LongAdder()).increment();
}
System.out.println(occurances);
} //main
}
'자바(JAVA)' 카테고리의 다른 글
[자바(Java)] static (0) | 2023.02.20 |
---|---|
[자바(Java)] equals , hashcode (0) | 2023.02.19 |
[자바(Java)] 디버그(debug) (0) | 2023.02.09 |
[자바(Java)] 연산자 (0) | 2023.02.06 |
[자바(Java)] DateTime (0) | 2023.02.06 |