ã¿ããªã®ã³ãŒããŒïŒ
ææ¥ã¯ãã»ãŒèšå¿µæ¥ã¹ããªãŒã ã®
ãJavaéçºè
ãã³ãŒã¹ãã¹ã ãŒãºã«éå§ããŸã-æšå¹Ž4æä»¥æ¥6åé£ç¶ã§ãã ãããŠããã¯ãç§ãã¡ãããªããšå
±æããæãè峿·±ãè³æãåã³éžæãã翻蚳ããããšãæå³ããŸãã
è¡ããïŒ
ãã®ã¬ã€ãã¯ããã«ãã¹ã¬ããããã°ã©ã ã䜿çšããJavaéçºè
ããäžŠè¡æ§ã®åºæ¬æŠå¿µãšãã®äœ¿ç𿹿³ãçè§£ããã®ã«åœ¹ç«ã¡ãŸãã æšæºã©ã€ãã©ãªãžã®ãªã³ã¯ã䜿çšããŠãJavaèšèªã®éèŠãªåŽé¢ã«ã€ããŠåŠç¿ããŸãã
ã»ã¯ã·ã§ã³1ãšã³ããªãŒJavaã¯åœåãããã¹ã¬ãããããã¯ãªã©ã®äž»èŠãªäžŠè¡æ§ã®æŠå¿µããµããŒãããŠããŸãã ãã®ã¬ã€ãã¯ããã«ãã¹ã¬ããããã°ã©ã ã䜿çšããJavaéçºè
ããäžŠè¡æ§ã®åºæ¬æŠå¿µãšãã®äœ¿ç𿹿³ãçè§£ããã®ã«åœ¹ç«ã¡ãŸãã
ã»ã¯ã·ã§ã³2ã³ã³ã»ããã®ã³ã³ã»ãã | 説æ |
---|
ååæ§ïŒååæ§ïŒ | ã¢ãããã¯æäœã¯ãå®å
šã«å®è¡ãããããŸã£ããå®è¡ãããªãæäœã§ãããéšåçãªå®è¡ã¯äžå¯èœã§ãã |
å¯èŠæ§ | ããã¹ã¬ãããå¥ã®ã¹ã¬ããã«ãã£ãŠè¡ããã倿ŽãèŠãæ¡ä»¶ |
衚1ïŒåæå®è¡æ§ã®æŠå¿µ
ç«¶åç¶æ
ç«¶åç¶æ
ã¯ãåããªãœãŒã¹ãè€æ°ã®ã¹ã¬ããã§åæã«äœ¿çšãããå Žåã«çºçããåã¹ã¬ããã®ã¢ã¯ã·ã§ã³ã®é åºã«ãã£ãŠã¯ãããã€ãã®çµæãåŸãããå ŽåããããŸãã 以äžã®ã³ãŒãã¯ã¹ã¬ããã»ãŒãã§ã¯ãªãããã£ãŒã«ããé
å»¶åæåãã
check-then-act
ïŒ
null
ã確èªããŠããåæåããïŒã¯
ã¢ãããã¯ã§ã¯ãªãããã
value
倿°ã¯è€æ°ååæåã§ããŸãã
class Lazy <T> { private volatile T value; T get() { if (value == null) value = initialize(); return value; } }
ããŒã¿ç«¶åããŒã¿ã®ç«¶åã¯ã2ã€ä»¥äžã®ã¹ã¬ãããåæããã«åãéæçµå€æ°ã«ã¢ã¯ã»ã¹ããããšãããšãã«çºçããŸãã åæã®æ¬ åŠã¯
ãä»ã®ã¹ã¬ããã«ã¯
èŠããªã倿Žããããããå€ãããŒã¿ã®èªã¿åããåŒãèµ·ãããç¡éã«ãŒããããŒã¿æ§é ã®æå·ããŸãã¯äžæ£ç¢ºãªèšç®ãåŒãèµ·ããå¯èœæ§ããããŸãã ãã®ã³ãŒãã¯ãèªã¿åãã¹ããªãŒã ãã¹ã¬ããã®æžãæãã«ãã倿Žã«æ°ä»ããªãå Žåããããããç¡éã«ãŒãã«ã€ãªããå¯èœæ§ããããŸãã
class Waiter implements Runnable { private boolean shouldFinish; void finish() { shouldFinish = true; } public void run() { long iteration = 0; while (!shouldFinish) { iteration++; } System.out.println("Finished after: " + iteration); } } class DataRace { public static void main(String[] args) throws InterruptedException { Waiter waiter = new Waiter(); Thread waiterThread = new Thread(waiter); waiterThread.start(); waiter.finish(); waiterThread.join(); } }
ã»ã¯ã·ã§ã³3Javaã¡ã¢ãªã¢ãã«ïŒå¶ç¶ã®é¢ä¿Javaã¡ã¢ãªã¢ãã«ã¯ããã£ãŒã«ãã®èªã¿åã/æžã蟌ã¿ãã¢ãã¿ãŒã§ã®åæãªã©ã®ã¢ã¯ã·ã§ã³ã«é¢ããŠå®çŸ©ãããŸãã ã¢ã¯ã·ã§ã³ã¯ãäºåã«çºçããé¢ä¿ïŒä»¥åã«å®è¡ãããïŒã䜿çšããŠé åºä»ããããŸããããã¯ãã¹ã¬ãããå¥ã®ã¹ã¬ããã®ã¢ã¯ã·ã§ã³ã®çµæã確èªããã¿ã€ãã³ã°ãšãæ£ããåæãããããã°ã©ã ã説æããããã«äœ¿çšã§ããŸãã
HAPPENS-BEFOREãªã¬ãŒã·ã§ã³ãºã«ã¯ä»¥äžã®ããããã£ããããŸãïŒ- ã¹ã¬ããïŒstartã®åŒã³åºãã¯ããã®ã¹ã¬ããã®ã¢ã¯ã·ã§ã³ã®åã«çºçããŸãã
- ã¢ãã¿ãŒã¯ãåãã¢ãã¿ãŒã®åŸç¶ã®ãã£ããã£ã®åã«æ»ããŸãã
- æ®çºæ§å€æ°ãžã®æžã蟌ã¿ã¯ããã®åŸã®æ®çºæ§å€æ°ã®èªã¿åãã®åã«çºçããŸãã
- æåŸã®å€æ°ãžã®æžã蟌ã¿ã¯ããªããžã§ã¯ããªã³ã¯ã®çºè¡åã«çºçããŸãã
- ã¹ã¬ããå
ã®ãã¹ãŠã®ã¢ã¯ã·ã§ã³ã¯ããã®ã¹ã¬ããã®ã¹ã¬ããïŒjoinããæ»ããŸã§å®è¡ãããŸãã
ã€ã¡ãŒãž1ã§ã¯ã
Action X
ã¯
Action Y
åã«çºçããããã
Thread 2
ã§ã¯ã
Action Y
ã®å³åŽã«ãããã¹ãŠã®æäœã«ã
Thread 1
Action X
ã®å·ŠåŽã«ãããã¹ãŠã®æäœã衚瀺ãããŸãã
ç»å1ïŒåã®äŸ
ã»ã¯ã·ã§ã³4æšæºåææ©èœsynchronized
ããŒã¯ãŒãsynchronized
ãç°ãªãã¹ã¬ãããåãã³ãŒããããã¯ãåæã«å®è¡ããªãããã«ããããã«äœ¿çšãããŸãã ïŒåæãããã¯ã«å
¥ãããšã§ïŒããã¯ãåãåã£ãå Žåããã®ããã¯ãé©çšãããããŒã¿ã¯æä»ã¢ãŒãã§åŠçããããããæäœã¯ã¢ãããã¯ãšèŠãªãããŸãã ãŸããåãããã¯ãåãåã£ãåŸãä»ã®ã¹ã¬ãããæäœã®çµæã確èªã§ããããã«ããŸãã
class AtomicOperation { private int counter0; private int counter1; void increment() { synchronized (this) { counter0++; counter1++; } } }
synchronizedããŒã¯ãŒãã¯ãã¡ãœããã¬ãã«ã§å±éããããšãã§ããŸãã
æ¹æ³ã®çš®é¡ | ã¢ãã¿ãŒãšããŠäœ¿çšããããªã³ã¯ |
---|
éç | Classãªããžã§ã¯ããžã®åç
§<ïŒ> |
ééç | ãã®ãªã³ã¯ |
衚2ïŒã¡ãœããå
šäœãåæããããšãã«äœ¿çšãããã¢ãã¿ãŒããã¯ã¯åå
¥å¯èœã§ãããããã¹ã¬ããã«ãã§ã«ããã¯ãå«ãŸããŠããå Žåã¯ãåã³ããã¯ãæ£åžžã«ååŸã§ããŸãã
class Reentrantcy { synchronized void doAll() { doFirst(); doSecond(); } synchronized void doFirst() { System.out.println("First operation is successful."); } synchronized void doSecond() { System.out.println("Second operation is successful."); } }
ç«¶åã®ã¬ãã«ã¯ãã¢ãã¿ãŒã®ãã£ããã£æ¹æ³ã«åœ±é¿ããŸãã
ç¶æ
| 説æ |
---|
åæå | 誰ãæç²ãããªããªããŸã§äœæãããŸããã |
åã£ã | æŠãã¯ãªããããã¯ã«ãã£ãŠä¿è·ãããã³ãŒãã¯1ã€ã®ã¹ã¬ããã®ã¿ã«ãã£ãŠå®è¡ãããŸãã ãã£ããã£ããã®ã«æãå®ãã |
èã | ã¢ãã¿ãŒã¯ãæŠããªãã§è€æ°ã®ã¹ã¬ããã«ãã£ãŠãã£ããã£ãããŸãã ããã¯ã«ã¯æ¯èŒçå®äŸ¡ãªCASã䜿çšãããŸãã |
倪ã | éäºããããŸãã JVMã¯OSãã¥ãŒããã¯ã¹ãèŠæ±ããOSã¹ã±ãžã¥ãŒã©ãã¹ã¬ããããŒãã³ã°ãšãŠã§ã€ã¯ã¢ãããåŠçã§ããããã«ããŸãã |
衚3ïŒã¢ãã¿ãŒã¹ããŒã¿ã¹wait/notify
wait/notify/notifyAll
ã¯ã
Object
ã¯ã©ã¹ã§å®£èšãããŠããŸãã
wait
ãã¹ã¬ããã匷å¶çã«
WAITING
ãŸãã¯
TIMED_WAITING
ã«ç§»è¡ãããããã«äœ¿çšãããŸãïŒã¿ã€ã ã¢ãŠãå€ãæž¡ãããå ŽåïŒã ã¹ã¬ãããèµ·åããã«ã¯ã次ã®ã¢ã¯ã·ã§ã³ã®ãããããå®è¡ã§ããŸãã
- å¥ã®ã¹ã¬ãããnotifyãåŒã³åºããšãã¢ãã¿ãŒã§åŸ
æ©ããŠããä»»æã®ã¹ã¬ãããèµ·åããŸãã
- å¥ã®ã¹ã¬ãããnotifyAllãåŒã³åºããã¢ãã¿ãŒã§åŸ
æ©ããŠãããã¹ãŠã®ã¹ã¬ãããèµ·åããŸãã
- ã¹ã¬ããïŒå²ã蟌ã¿ãåŒã³åºãããŸãã ãã®å ŽåãInterruptedExceptionãã¹ããŒãããŸãã
æãäžè¬çãªäŸã¯æ¡ä»¶ä»ãã«ãŒãã§ãã
class ConditionLoop { private boolean condition; synchronized void waitForCondition() throws InterruptedException { while (!condition) { wait(); } } synchronized void satisfyCondition() { condition = true; notifyAll(); } }
- ãªããžã§ã¯ãã«å¯ŸããŠ
wait/notify/notifyAll
ã䜿çšããã«ã¯ãæåã«ãªããžã§ã¯ããããã¯ããå¿
èŠãããããšã«æ³šæããŠwait/notify/notifyAll
ã - ã«ãŒãå
ã§åžžã«åŸ
æ©ããŠãå®äºãäºæ³ãããç¶æ
ã確èªããŠãã ããã ããã¯ãåŸ
æ©ã®éå§åã«å¥ã®ã¹ã¬ãããæ¡ä»¶ãæºãããŠããå Žåã®åæã®åé¡ã«é¢ä¿ããŸãã ããã«ãããã«ãããçºçããå¯èœæ§ãããïŒããã³çºçããïŒä»éçãªç®èŠãããã³ãŒããä¿è·ãããŸãã
- notify / notifyAllãåŒã³åºãåã«ãåžžã«åŸ
æ©æ¡ä»¶ãæºãããŠããããšã確èªããŠãã ããã ããããªããšãéç¥ãçºçããŸãããã¹ã¬ããã¯åŸ
æ©ã«ãŒãããšã¹ã±ãŒãã§ããŸããã
ããŒã¯ãŒãvolatile
volatile
ã¯
å¯èŠæ§ã®åé¡ã解決ããå€ã®å€æŽã
ã¢ãããã¯ã«ããŸããããã¯ãçºçåã®é¢ä¿ãããããã§ããvolatile倿°ãžã®æžã蟌ã¿ã¯ãvolatile倿°ã®åŸç¶ã®èªã¿åãã®åã«çºçããŸãã ãããã£ãŠã次åãã£ãŒã«ããèªã¿åããããšãã«ãææ°ã®ã¬ã³ãŒãã«ãã£ãŠèšå®ãããå€ã衚瀺ãããããã«ãªããŸãã
class VolatileFlag implements Runnable { private volatile boolean shouldStop; public void run() { while (!shouldStop) {
ååæ§java.util.concurrent.atomic
ããã±ãŒãžã«ã¯ã
volatile
ããã«ãããã¯ããã«åäžã®å€ã§è€åã¢ãããã¯ã¢ã¯ã·ã§ã³ããµããŒãããã¯ã©ã¹ã®ã»ãããå«ãŸããŠããŸãã
AtomicXXXã¯ã©ã¹ã䜿çšããŠãã¢ãããã¯
check-then-act
ã¶ã³ã
check-then-act
æäœãå®è£
ã§ããŸãã
class CheckThenAct { private final AtomicReference<String> value = new AtomicReference<>(); void initialize() { if (value.compareAndSet(null, "Initialized value")) { System.out.println("Initialized only once."); } } }
AtomicInteger
ãš
AtomicLong
äž¡æ¹ã«ã¢ãããã¯ãªã€ã³ã¯ãªã¡ã³ã/ãã¯ãªã¡ã³ãæäœããããŸãïŒ
class Increment { private final AtomicInteger state = new AtomicInteger(); void advance() { int oldState = state.getAndIncrement(); System.out.println("Advanced: '" + oldState + "' -> '" + (oldState + 1) + "'."); } }
ã«ãŠã³ã¿ãŒãå¿
èŠã§ãã¢ãããã¯ã«å€ãååŸããå¿
èŠããªãå Žåã¯ã
AtomicLong/AtomicInteger
代ããã«
AtomicLong/AtomicInteger
䜿çšãæ€èšããŠ
AtomicLong/AtomicInteger
ã
LongAdder
ã¯ãããã€ãã®ã»ã«ã®å€ãåŠçããå¿
èŠã«å¿ããŠãã®æ°ãå¢ãããŸãããããã£ãŠãç«¶äºãæ¿ããå Žåã«å¹æçã§ãã
ThreadLocal
ããŒã¿ãã¹ããªãŒã ã«ä¿åããããã¯ããªãã·ã§ã³ã«ãã1ã€ã®æ¹æ³ã¯ã
ThreadLocal
ã¹ãã¬ãŒãžã䜿çšããããšã§ãã æŠå¿µçã«ã
ThreadLocal
ã¯ãåã¹ã¬ãããç¬èªã®ããŒãžã§ã³ã®å€æ°ãæã£ãŠãããã®ããã«æ©èœããŸãã
ThreadLocal
éåžžããçŸåšã®ãã©ã³ã¶ã¯ã·ã§ã³ããªã©ã®åã¹ã¬ããã®å€ããã®ä»ã®ãªãœãŒã¹ããã£ããã£ããããã«äœ¿çšãããŸãã ããã«ããããŒã«ãŠã³ã¿ãçµ±èšããŸãã¯èå¥åãžã§ãã¬ãŒã¿ãç¶æããããã«äœ¿çšãããŸãã
class TransactionManager { private final ThreadLocal<Transaction> currentTransaction = ThreadLocal.withInitial(NullTransaction::new); Transaction currentTransaction() { Transaction current = currentTransaction.get(); if (current.isNull()) { current = new TransactionImpl(); currentTransaction.set(current); } return current; } }
ã»ã¯ã·ã§ã³5å®å
šãªå
¬éãªããžã§ã¯ããå
¬éãããšãçŸåšã®ã¹ã³ãŒãå€ã§ãªã³ã¯ãå©çšå¯èœã«ãªããŸãïŒããšãã°ãã²ãã¿ãŒãããªã³ã¯ãè¿ãïŒã ãªããžã§ã¯ããå®å
šã«å
¬éããã«ã¯ïŒå®å
šã«äœæãããå Žåã®ã¿ïŒãåæãå¿
èŠã«ãªãå ŽåããããŸãã ãããªã±ãŒã·ã§ã³ã®ã»ãã¥ãªãã£ã¯ã次ã䜿çšããŠå®çŸã§ããŸãã
- éçåæååã ã¯ã©ã¹ã®åæåã¯æä»ããã¯äžã§å®è¡ããããããéç倿°ãåæåã§ããã¹ã¬ããã¯1ã€ã ãã§ãã
class StaticInitializer {
- æ®çºæ§ãã£ãŒã«ãã èªã¿åãã¹ããªãŒã ã¯åžžã«æåŸã®å€ãèªã¿åããŸããããã¯ãæ®çºæ§å€æ°ãžã®æžã蟌ã¿ãåŸç¶ã®èªã¿åãã®åïŒçºçåïŒã«çºçããããã§ãã
class Volatile { private volatile String state; void setState(String state) { this.state = state; } String getState() { return state; } }
- ååæ§ã ããšãã°ã
AtomicInteger
ã¯å€ãvolatileãã£ãŒã«ãã«æ ŒçŽãããããvolatile倿°ã®èŠåãããã§é©çšã§ããŸãã
class Atomics { private final AtomicInteger state = new AtomicInteger(); void initializeState(int state) { this.state.compareAndSet(0, state); } int getState() { return state.get(); } }
class Final { private final String state; Final(String state) { this.state = state; } String getState() { return state; } }
ãã®ãªã³ã¯ãäœæäžã«èžçºããªãããšã確èªããŠãã ããã
class ThisEscapes { private final String name; ThisEscapes(String name) { Cache.putIntoCache(this); this.name = name; } String getName() { return name; } } class Cache { private static final Map<String, ThisEscapes> CACHE = new ConcurrentHashMap<>(); static void putIntoCache(ThisEscapes thisEscapes) {
- æ£ããåæããããã£ãŒã«ãã
class Synchronization { private String state; synchronized String getState() { if (state == null) state = "Initial"; return state; } }
ã»ã¯ã·ã§ã³6äžå€ãªããžã§ã¯ãäžå€ãªããžã§ã¯ãã®æãæ³šç®ãã¹ãç¹æ§ã®1ã€ã¯
ã¹ã¬ããã®å®å
šæ§ã§ã ããããã£ãŠããªããžã§ã¯ãã®åæã¯äžèŠã§ãã äžå€ãªããžã§ã¯ãã®èŠä»¶ïŒ
- ãã¹ãŠã®ãã£ãŒã«ãã¯æçµãã£ãŒã«ãã§ãã
- ãã¹ãŠã®ãã£ãŒã«ãã¯ãå¯å€ãŸãã¯äžå€ã®ãªããžã§ã¯ãã§ããå¿
èŠããããŸããããªããžã§ã¯ãã®å¢çãè¶
ããŠã¯ãªããªããããäœæåŸã«ãªããžã§ã¯ãã®ç¶æ
ã倿Žããããšã¯ã§ããŸããã
- ãã®ãªã³ã¯ã¯äœææã«æ¶ããŸããã
- ã¯ã©ã¹ã¯æçµã¯ã©ã¹ãªã®ã§ããµãã¯ã©ã¹ã§ãã®åäœãåå®çŸ©ããããšã¯ã§ããŸããã
äžå€ãªããžã§ã¯ãã®äŸïŒ
ã»ã¯ã·ã§ã³7ã¹ããªãŒã java.lang.Thread
ã¯ã©ã¹ã¯ãã¢ããªã±ãŒã·ã§ã³ãŸãã¯JVMã¹ã¬ããã衚ãããã«äœ¿çšãããŸãã ã³ãŒãã¯ãåžžã«ããã€ãã®Threadã¯ã©ã¹ã®ã³ã³ããã¹ãã§å®è¡ãããŸãïŒçŸåšã®ã¹ã¬ãããååŸããã«ã¯ã
Thread#currentThread()).
䜿çšã§ããŸã
Thread#currentThread()).
ç¶æ
| 説æ |
---|
æ°å | éå§ããŸããã§ããã |
å®è¡å¯èœ | 皌åããŠããŸãã |
ãããã¯ããã | ã¢ãã¿ãŒã§åŸ
æ©äž-圌ã¯ããã¯ãååŸããŠãã¯ãªãã£ã«ã«ã»ã¯ã·ã§ã³ã«å
¥ãããšããŠããŸãã |
åŸ
ã£ãŠããŸã | ç¹å®ã®ã¢ã¯ã·ã§ã³ãå¥ã®ã¹ã¬ããã«ãã£ãŠå®è¡ãããã®ãåŸ
ã£ãŠããŸãïŒnotify / notifyAllãLockSupportïŒunparkïŒã |
TIMED_WAITING | WAITINGãšåãã§ãããã¿ã€ã ã¢ãŠãããããŸãã |
çµäºããŸãã | æ¢ãŸã£ã |
衚4ïŒã¹ããªãŒã ã®ç¶æ
ã¹ããªãŒã æ¹åŒ | 説æ |
---|
å§ãã | Threadã¯ã©ã¹ã®ã€ã³ã¹ã¿ã³ã¹ãéå§ããrunïŒïŒã¡ãœãããå®è¡ããŸãã |
åå ãã | ã¹ããªãŒã ã®çµãããŸã§ãããã¯ããŸãã |
å²ã蟌ã | ã¹ããªãŒã ãäžæããŸãã å²ã蟌ã¿ã«å¿çããã¡ãœããã§ã¹ã¬ããããããã¯ãããŠããå Žåãå¥ã®ã¹ã¬ããã§InterruptedExceptionãã¹ããŒãããŸããããã§ãªãå Žåã¯ãå²ã蟌ã¿ã¹ããŒã¿ã¹ãèšå®ãããŸãã |
忢ãäžæåæ¢ãåéãç Žæ£ | ãããã®æ¹æ³ã¯ãã¹ãп代é
ãã§ãã åé¡ã®ãããŒã®ç¶æ
ã«å¿ããŠãå±éºãªæäœãå®è¡ããŸãã 代ããã«ãThreadïŒinterruptïŒïŒãŸãã¯volatileãã©ã°ã䜿çšããŠãã¹ã¬ããã«äœããã¹ãããäŒããŸã |
衚5ïŒã¹ã¬ããèª¿æŽæ¹æ³ã¹ã¬ããèª¿æŽæ¹æ³InterruptedExceptionãåŠçããæ¹æ³ã¯ïŒ- å¯èœã§ããã°ãçŸåšã®ã¬ãã«ã§ãã¹ãŠã®ãªãœãŒã¹ãã¯ãªã¢ããã¹ã¬ãããçµäºããŸãã
- çŸåšã®ã¡ãœãããInterruptedExceptionãã¹ããŒããããšã宣èšããŸãã
- ã¡ãœãããInterruptedExceptionãçºçãããªãå ŽåãThread.currentThreadïŒïŒãInterruptïŒïŒãåŒã³åºããŠãå²ã蟌ã¿ãã©ã°ãtrueã«ãªã»ãããããã®ã¬ãã«ã§ããé©åãªäŸå€ãã¹ããŒããå¿
èŠããããŸãã ããé«ãã¬ãã«ã§å²ã蟌ã¿ãåŠçã§ããããã«ããã«ã¯ãtrueãã©ã°ãè¿ãããšãéåžžã«éèŠã§ãã
äºæããªãäŸå€ã®åŠçUncaughtExceptionHandler
ã§
UncaughtExceptionHandler
ã瀺ãããå Žåããããã¹ã¬ãããäžæãããããããã£ãããããªãäŸå€ã®éç¥ãåãåããŸãã
Thread thread = new Thread(runnable); thread.setUncaughtExceptionHandler((failedThread, exception) -> { logger.error("Caught unexpected exception in thread '{}'.", failedThread.getName(), exception); }); thread.start();
ã»ã¯ã·ã§ã³8掻åïŒæŽ»åïŒDeadlock
Deadlock
ããŸãã¯ãããããã¯ã¯ãè€æ°ã®ã¹ã¬ãããããããããããå¥ã®ã¹ã¬ããã«å±ãããªãœãŒã¹ãäºæããŠããå Žåã«çºçããŸãããã®ããããªãœãŒã¹ãšããããåŸ
æ©ããŠããã¹ã¬ããããã«ãŒãã圢æãããŸãã æãæçœãªã¿ã€ãã®ãªãœãŒã¹ã¯ãªããžã§ã¯ãã¢ãã¿ãŒã§ãããããã¯ãåŒãèµ·ãããªãœãŒã¹ïŒããšãã°ã
wait/notify
ïŒãé©åã§ãã
æœåšçãªãããããã¯ã®äŸïŒ
class Account { private long amount; void plus(long amount) { this.amount += amount; } void minus(long amount) { if (this.amount < amount) throw new IllegalArgumentException(); else this.amount -= amount; } static void transferWithDeadlock(long amount, Account first, Account second){ synchronized (first) { synchronized (second) { first.minus(amount); second.plus(amount); } } } }
åæã«æ¬¡ã®å Žåãçžäºããã¯ãçºçããŸãã
- 1ã€ã®ã¹ã¬ããã1ã€ã®ã¢ã«ãŠã³ãããå¥ã®ã¢ã«ãŠã³ãã«ããŒã¿ã転éããããšããŠããããã§ã«æåã®ã¢ã«ãŠã³ãã«ããã¯ããããŠããŸãã
- å¥ã®ã¹ã¬ããã2çªç®ã®ã¢ã«ãŠã³ãããæåã®ã¢ã«ãŠã³ãã«ããŒã¿ã転éããããšããŠããããã§ã«2çªç®ã®ã¢ã«ãŠã³ãã«ããã¯ããããŠããŸãã
ãããããã¯ãé²ãæ¹æ³ïŒ
- ããã¯é åº-åžžã«åãé åºã§ããã¯ããŸãã
class Account { private long id; private long amount;
- ã¿ã€ã ã¢ãŠãä»ãã®ãããã¯-ããã¯ãé©çšãããšãã«ç¡æéã«ãããã¯ããªãã§ãã ããããã¹ãŠã®ããã¯ãã§ããã ãæ©ãåé€ããŠå詊è¡ããããšããå§ãããŸãã
class Account { private long amount;
JVMã¯ã¢ãã¿ãŒã®çžäºããã¯ãæ€åºããã¢ãã¿ãŒã«é¢ããæ
å ±ãã¹ããªãŒã ãã³ãã«è¡šç€ºã§ããŸãã
Livelockããã³Stream Fastingã©ã€ãããã¯ã¯ãã¹ã¬ããããªãœãŒã¹ãžã®ã¢ã¯ã»ã¹ã®ããŽã·ãšãŒã·ã§ã³ã«å
šæéãè²»ããããã¹ã¬ãããå®éã«åé²ããªãããã«ãããããã¯ãçºèŠããŠåé¿ãããšãã«çºçããŸãã çµ¶é£ã¯ãã¹ã¬ãããé·æéãããã¯ãç¶ãããšçºçãããããäžéšã®ã¹ã¬ããã¯é²è¡ããã«ãstaræ»ãããŸãã
ã»ã¯ã·ã§ã³9java.util.concurrent
ã¹ã¬ããããŒã«ã¹ã¬ããããŒã«ã®ã¡ã€ã³ã€ã³ã¿ãŒãã§ã€ã¹ã¯
ExecutorService.java.util.concurrent
ãŸããæãäžè¬çãªæ§æã§ã¹ã¬ããããŒã«ãäœæããããã®ãã¡ã¯ããªã¡ãœãããå«ãéçExecutorsãã¡ã¯ããªãæäŸããŸãã
æ¹æ³ | 説æ |
---|
newSingleThreadExecutor | 1ã€ã®ã¹ã¬ããã®ã¿ãæã€ExecutorServiceãè¿ããŸãã |
newFixedThreadPool | ã¹ã¬ããã®æ°ãåºå®ãããExecutorServiceãè¿ããŸãã |
newCachedThreadPool | ããŸããŸãªãµã€ãºã®ã¹ã¬ããã®ããŒã«ãæã€ExecutorServiceãè¿ããŸãã |
newSingleThreadScheduledExecutor | åäžã®ã¹ã¬ããã§ScheduledExecutorServiceãè¿ããŸãã |
newScheduledThreadPool | ã¹ã¬ããã®ã¡ã€ã³ã»ãããå«ãScheduledExecutorServiceãè¿ããŸãã |
newWorkStealingPool | ãã£ãã·ã³ã°ã¿ã¹ã¯ExecutorServiceãè¿ããŸãã |
衚6ïŒéçãã¡ã¯ããªã¡ãœããã¹ã¬ããããŒã«ã®ãµã€ãºã決å®ãããšããã¢ããªã±ãŒã·ã§ã³ãå®è¡ãããŠãããã·ã³ã®è«çã³ã¢ã®æ°ã®ãµã€ãºã決å®ããããšã¯ãã°ãã°æçšã§ãã
Runtime.getRuntime().AvailableProcessors()
åŒã³åºãããšã«ãããJavaã§ãã®å€ãååŸã§ããŸãã
å®è£
| 説æ |
---|
ThreadPoolExecutor | ããã©ã«ãã®å®è£
ã§ã¯ããµã€ãºå€æŽã¹ã¬ããããŒã«ã1ã€ã®äœæ¥ãã¥ãŒãæåŠãããã¿ã¹ã¯ïŒRejectedExecutionHandlerçµç±ïŒããã³ã¹ã¬ããäœæïŒThreadFactoryçµç±ïŒã®ã«ã¹ã¿ã ããªã·ãŒã䜿çšãããŸãã |
ScheduledThreadPoolExecutor | 宿çãªã¿ã¹ã¯ãã¹ã±ãžã¥ãŒã«ããæ©èœãæäŸããæ¡åŒµThreadPoolExecutorã |
ãã©ãŒã¯ãžã§ã€ã³ããŒã« | ã¿ã¹ã¯ãçãããŒã«ïŒããŒã«å
ã®ãã¹ãŠã®ã¹ã¬ããã¯ãå²ãåœãŠãããã¿ã¹ã¯ãŸãã¯ä»ã®ã¢ã¯ãã£ããªã¿ã¹ã¯ã«ãã£ãŠäœæãããã¿ã¹ã¯ãèŠã€ããŠå®è¡ããããšããŸãã |
衚7ïŒã¹ã¬ããããŒã«ã®å®è£
ã¿ã¹ã¯ã¯ã
ExecutorService#submit
ã
ExecutorService#invokeAll
ãŸãã¯
ExecutorService#invokeAny
ã䜿çšããŠéä¿¡ãããŸãããããã«ã¯ãããŸããŸãªã¿ã€ãã®ã¿ã¹ã¯çšã®ãªãŒããŒããŒããããã€ããããŸãã
ã€ã³ã¿ãŒãã§ãŒã¹ | 説æ |
---|
å®è¡å¯èœ | æ»ãå€ã®ãªãã¿ã¹ã¯ã衚ããŸãã |
åŒã³åºãå¯èœ | æ»ãå€ãæã€èšç®ã衚ããŸãã ãŸããå
ã®äŸå€ãã¹ããŒããããããã§ãã¯æžã¿äŸå€ã®ã©ãããŒã¯å¿
èŠãããŸããã |
衚8ïŒæ©èœã¿ã¹ã¯ã€ã³ã¿ãŒãã§ã€ã¹Future
Future
ã¯éåæã³ã³ãã¥ãŒãã£ã³ã°ã®æœè±¡åã§ãã èšç®çµæãŸãã¯äŸå€ã®ããããã§ããã€ã§ãå©çšå¯èœãªèšç®ã®çµæã衚ããŸãã ã»ãšãã©ã®
ExecutorService
ã¡ãœããã¯ã
Future
ãæ»ãåãšããŠäœ¿çšããŸãã å°æ¥ã®çŸåšã®ç¶æ
ã調ã¹ãããã®ã¡ãœãããæäŸããããçµæãå©çšå¯èœã«ãªããŸã§ãããã¯ããŸãã
ExecutorService executorService = Executors.newSingleThreadExecutor(); Future<String> future = executorService.submit(() -> "result"); try { String result = future.get(1L, TimeUnit.SECONDS); System.out.println("Result is '" + result + "'."); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new RuntimeException(e); } catch (ExecutionException e) { throw new RuntimeException(e.getCause()); } catch (TimeoutException e) { throw new RuntimeException(e); } assert future.isDone();
ããã¯Lock
java.util.concurrent.locks
ããã±ãŒãžã«ã¯ãæšæºã®
Lock
ã€ã³ã¿ãŒãã§ã€ã¹ããããŸãã
ReentrantLock
å®è£
ã¯ãsynchronizedããŒã¯ãŒãã®æ©èœãè€è£œããŸãããããã¯ã¹ããŒã¿ã¹æ
å ±ã®ååŸãéããããã³ã°
tryLock()
ããã¯ã®äžæãªã©ã®è¿œå æ©èœãæäŸããŸãã ReentrantLockã®æç€ºçãªã€ã³ã¹ã¿ã³ã¹ã®äœ¿çšäŸïŒ
class Counter { private final Lock lock = new ReentrantLock(); private int value; int increment() { lock.lock(); try { return ++value; } finally { lock.unlock(); } } }
ReadWriteLockjava.util.concurrent.locks
ããã±ãŒãžã«ã¯ãReadWriteLockã€ã³ã¿ãŒãã§ã€ã¹ïŒããã³ReentrantReadWriteLockå®è£
ïŒãå«ãŸããŠããŸããããã¯ãèªã¿åããšæžã蟌ã¿ã®ããã¯ã®ãã¢ã«ãã£ãŠæ±ºå®ãããéåžžã¯è€æ°ã®ãªãŒããŒãåæã«èªã¿åããèš±å¯ããŸãããã©ã€ã¿ãŒã¯1人ã®ã¿èš±å¯ããŸãã
class Statistic { private final ReadWriteLock lock = new ReentrantReadWriteLock(); private int value; void increment() { lock.writeLock().lock(); try { value++; } finally { lock.writeLock().unlock(); } } int current() { lock.readLock().lock(); try { return value; } finally { lock.readLock().unlock(); } } }
CountDownLatch
CountDownLatch
.
await()
, , 0. ( )
countDown()
, . , 0. , .
CompletableFuture
CompletableFuture
. Future, â , , , . (
CompletableFuture#supplyAsync/runAsync
), (
*async
) , (
ForkJoinPool#commonPool
).
,
CompletableFuture
, ,
*async
, .
future
,
CompletableFuture#allOf
,
future
, ,
future
,
CompletableFuture#anyOf
, , -
future
.
ExecutorService executor0 = Executors.newWorkStealingPool(); ExecutorService executor1 = Executors.newWorkStealingPool();
â
Collections#synchronized*
. ,
java.util.concurrent
, .
å®è£
| 説æ |
---|
CopyOnWriteArrayList | , ( , ). . |
9: java.util.concurrent
| 説æ |
---|
ConcurrentHashMap | -. , , . CAS- ( ), ( ). |
ConcurrentSkipListMap | Map, TreeMap. TreeMap, , . |
10: java.util.concurrent
| 説æ |
---|
CopyOnWriteArraySet | CopyOnWriteArrayList, copy-on-write Set. |
ConcurrentSkipListSet | ConcurrentSkipListMap, Set. |
11: java.util.concurrent
Map:
Set<T> concurrentSet = Collections.newSetFromMap(new ConcurrentHashMap<T, Boolean>());
«» «». « , » (FIFO).
BlockingQueue
Queue
, , , ( ) ( ).
BlockingQueue
, , , - .
å®è£
| 説æ |
---|
ConcurrentLinkedQueue | , . |
LinkedBlockingQueue | , . |
PriorityBlockingQueue | , . , Comparator, ( FIFO). |
DelayQueue | , . , . |
SynchronousQueue | -, , . , . . |
12: java.util.concurrent
çµãã
.
ããããšã