[{"data":1,"prerenderedAt":959},["ShallowReactive",2],{"blog-\u002Fblog\u002Fjava-concurrency-threads-synchronization":3},{"id":4,"title":5,"body":6,"description":944,"difficulty":945,"extension":946,"framework":947,"frameworkSlug":49,"meta":948,"navigation":949,"order":57,"path":950,"qaPath":951,"seo":952,"stem":953,"subtopic":954,"topic":955,"topicSlug":956,"updated":957,"__hash__":958},"blog\u002Fblog\u002Fjava-concurrency-threads-synchronization.md","Java Concurrency — Threads, Synchronization & the Executor Framework",{"type":7,"value":8,"toc":932},"minimark",[9,14,18,22,44,107,128,132,143,201,230,234,250,298,314,318,332,341,351,355,374,441,462,466,476,564,597,670,685,689,715,771,784,788,808,846,869,873,928],[10,11,13],"h2",{"id":12},"java-concurrency-and-threads","Java concurrency and threads",[15,16,17],"p",{},"Concurrency lets a program do many things at once, but it also opens the door to race\nconditions, deadlocks, and visibility bugs that only appear under load. Java gives you\nlow-level threads and a rich high-level toolkit (executors, atomics, concurrent\ncollections) to manage it. This guide builds from threads up to the executor framework and\nthe memory model that makes it all correct.",[10,19,21],{"id":20},"creating-threads","Creating threads",[15,23,24,25,29,30,33,34,36,37,43],{},"Two basic approaches: extend ",[26,27,28],"code",{},"Thread",", or implement ",[26,31,32],{},"Runnable"," and pass it to a ",[26,35,28],{},".\n",[38,39,40,42],"strong",{},[26,41,32],{}," is preferred"," — it separates the task from the thread and works with\nexecutors.",[45,46,51],"pre",{"className":47,"code":48,"language":49,"meta":50,"style":50},"language-java shiki shiki-themes github-light github-dark","Runnable task = () -> System.out.println(\"working\");\nnew Thread(task).start();\n","java","",[26,52,53,89],{"__ignoreMap":50},[54,55,58,62,66,69,72,75,79,82,86],"span",{"class":56,"line":57},"line",1,[54,59,61],{"class":60},"sVt8B","Runnable task ",[54,63,65],{"class":64},"szBVR","=",[54,67,68],{"class":60}," () ",[54,70,71],{"class":64},"->",[54,73,74],{"class":60}," System.out.",[54,76,78],{"class":77},"sScJk","println",[54,80,81],{"class":60},"(",[54,83,85],{"class":84},"sZZnC","\"working\"",[54,87,88],{"class":60},");\n",[54,90,92,95,98,101,104],{"class":56,"line":91},2,[54,93,94],{"class":64},"new",[54,96,97],{"class":77}," Thread",[54,99,100],{"class":60},"(task).",[54,102,103],{"class":77},"start",[54,105,106],{"class":60},"();\n",[15,108,109,112,113,116,117,120,121,123,124,127],{},[26,110,111],{},"start()"," creates a ",[38,114,115],{},"new thread"," and runs ",[26,118,119],{},"run()"," on it; calling ",[26,122,119],{}," directly just\nexecutes on the current thread — no concurrency. A thread can be started only once. In\nreal code you rarely create threads by hand; you submit tasks to an ",[26,125,126],{},"ExecutorService",".",[10,129,131],{"id":130},"race-conditions-and-synchronization","Race conditions and synchronization",[15,133,134,135,138,139,142],{},"A ",[38,136,137],{},"race condition"," happens when multiple threads access shared mutable state and the\nresult depends on timing. Operations that look atomic (",[26,140,141],{},"count++",") are actually\nread-modify-write sequences that can interleave and lose updates.",[45,144,146],{"className":47,"code":145,"language":49,"meta":50,"style":50},"class Counter {\n  private int count;\n  synchronized void inc() { count++; }  \u002F\u002F mutual exclusion + visibility\n}\n",[26,147,148,159,170,195],{"__ignoreMap":50},[54,149,150,153,156],{"class":56,"line":57},[54,151,152],{"class":64},"class",[54,154,155],{"class":77}," Counter",[54,157,158],{"class":60}," {\n",[54,160,161,164,167],{"class":56,"line":91},[54,162,163],{"class":64},"  private",[54,165,166],{"class":64}," int",[54,168,169],{"class":60}," count;\n",[54,171,173,176,179,182,185,188,191],{"class":56,"line":172},3,[54,174,175],{"class":64},"  synchronized",[54,177,178],{"class":64}," void",[54,180,181],{"class":77}," inc",[54,183,184],{"class":60},"() { count",[54,186,187],{"class":64},"++",[54,189,190],{"class":60},"; }  ",[54,192,194],{"class":193},"sJ8bj","\u002F\u002F mutual exclusion + visibility\n",[54,196,198],{"class":56,"line":197},4,[54,199,200],{"class":60},"}\n",[15,202,203,208,209,212,213,216,217,220,221,224,225,229],{},[38,204,205],{},[26,206,207],{},"synchronized"," enforces mutual exclusion via an object's ",[38,210,211],{},"monitor lock"," — only one\nthread holds it at a time — and establishes a ",[38,214,215],{},"happens-before"," relationship guaranteeing\nvisibility. An instance method locks on ",[26,218,219],{},"this","; a static synchronized method locks on the\n",[26,222,223],{},"Class"," object (so they use ",[226,227,228],"em",{},"different"," locks — a common bug).",[10,231,233],{"id":232},"volatile-vs-synchronized","volatile vs synchronized",[15,235,236,241,242,245,246,249],{},[38,237,238],{},[26,239,240],{},"volatile"," guarantees ",[38,243,244],{},"visibility and ordering"," for a single variable — writes are\nimmediately visible, with no caching or reordering — but ",[38,247,248],{},"not atomicity"," for compound\noperations.",[45,251,253],{"className":47,"code":252,"language":49,"meta":50,"style":50},"volatile boolean running = true;  \u002F\u002F flag — visibility is enough\nvolatile int count;\ncount++;                          \u002F\u002F still a race — read-modify-write\n",[26,254,255,277,285],{"__ignoreMap":50},[54,256,257,259,262,265,267,271,274],{"class":56,"line":57},[54,258,240],{"class":64},[54,260,261],{"class":64}," boolean",[54,263,264],{"class":60}," running ",[54,266,65],{"class":64},[54,268,270],{"class":269},"sj4cs"," true",[54,272,273],{"class":60},";  ",[54,275,276],{"class":193},"\u002F\u002F flag — visibility is enough\n",[54,278,279,281,283],{"class":56,"line":91},[54,280,240],{"class":64},[54,282,166],{"class":64},[54,284,169],{"class":60},[54,286,287,290,292,295],{"class":56,"line":172},[54,288,289],{"class":60},"count",[54,291,187],{"class":64},[54,293,294],{"class":60},";                          ",[54,296,297],{"class":193},"\u002F\u002F still a race — read-modify-write\n",[15,299,300,301,303,304,306,307,309,310,313],{},"Use ",[26,302,240],{}," for flags published once (the classic stop-flag); use ",[26,305,207],{}," or\natomics when you need atomic compound updates. ",[26,308,207],{}," adds ",[38,311,312],{},"mutual exclusion","\nand can guard multiple variables, at the cost of blocking.",[10,315,317],{"id":316},"deadlock-livelock-starvation","Deadlock, livelock, starvation",[15,319,134,320,323,324,327,328,331],{},[38,321,322],{},"deadlock"," is two+ threads each holding a lock the other needs, waiting forever. It\nrequires four conditions (mutual exclusion, hold-and-wait, no preemption, circular wait);\nbreak one — usually by acquiring locks in a ",[38,325,326],{},"consistent global order"," or using ",[26,329,330],{},"tryLock","\nwith a timeout — to prevent it.",[45,333,335],{"className":47,"code":334,"language":49,"meta":50,"style":50},"\u002F\u002F Thread 1: lock A then B  |  Thread 2: lock B then A  -> deadlock\n",[26,336,337],{"__ignoreMap":50},[54,338,339],{"class":56,"line":57},[54,340,334],{"class":193},[15,342,343,346,347,350],{},[38,344,345],{},"Starvation"," is a thread perpetually denied resources; ",[38,348,349],{},"livelock"," is threads actively\nrunning but never progressing (repeatedly responding to each other). Fixes include\nfairness policies, randomized back-off, and bounded retries.",[10,352,354],{"id":353},"coordination-waitnotify-and-higher-level-tools","Coordination: wait\u002Fnotify and higher-level tools",[15,356,357,360,361,360,364,367,368,373],{},[26,358,359],{},"wait()","\u002F",[26,362,363],{},"notify()",[26,365,366],{},"notifyAll()"," coordinate threads on an object's monitor and must be\ncalled while holding its lock; always re-check the condition in a ",[38,369,370],{},[26,371,372],{},"while"," loop\n(spurious wakeups). But you rarely need them — high-level utilities are safer:",[45,375,377],{"className":47,"code":376,"language":49,"meta":50,"style":50},"\u002F\u002F producer\u002Fconsumer with a BlockingQueue — no manual wait\u002Fnotify\nBlockingQueue\u003CTask> queue = new LinkedBlockingQueue\u003C>(100);\nqueue.put(task);        \u002F\u002F blocks if full\nTask t = queue.take();  \u002F\u002F blocks if empty\n",[26,378,379,384,408,422],{"__ignoreMap":50},[54,380,381],{"class":56,"line":57},[54,382,383],{"class":193},"\u002F\u002F producer\u002Fconsumer with a BlockingQueue — no manual wait\u002Fnotify\n",[54,385,386,389,392,395,397,400,403,406],{"class":56,"line":91},[54,387,388],{"class":60},"BlockingQueue\u003C",[54,390,391],{"class":64},"Task",[54,393,394],{"class":60},"> queue ",[54,396,65],{"class":64},[54,398,399],{"class":64}," new",[54,401,402],{"class":60}," LinkedBlockingQueue\u003C>(",[54,404,405],{"class":269},"100",[54,407,88],{"class":60},[54,409,410,413,416,419],{"class":56,"line":172},[54,411,412],{"class":60},"queue.",[54,414,415],{"class":77},"put",[54,417,418],{"class":60},"(task);        ",[54,420,421],{"class":193},"\u002F\u002F blocks if full\n",[54,423,424,427,429,432,435,438],{"class":56,"line":197},[54,425,426],{"class":60},"Task t ",[54,428,65],{"class":64},[54,430,431],{"class":60}," queue.",[54,433,434],{"class":77},"take",[54,436,437],{"class":60},"();  ",[54,439,440],{"class":193},"\u002F\u002F blocks if empty\n",[15,442,443,446,447,450,451,454,455,458,459,461],{},[26,444,445],{},"CountDownLatch"," (wait for N tasks, one-shot), ",[26,448,449],{},"CyclicBarrier"," (threads wait for each\nother, reusable), and ",[26,452,453],{},"Semaphore"," (limit concurrent access) cover most coordination needs.\nNote ",[26,456,457],{},"sleep()"," pauses without releasing locks, while ",[26,460,359],{}," releases the lock.",[10,463,465],{"id":464},"the-executor-framework","The executor framework",[15,467,468,469,471,472,475],{},"An ",[26,470,126],{}," manages a ",[38,473,474],{},"pool of reusable threads"," and a task queue, so you\nsubmit work instead of creating threads. This caps thread count, reuses threads, and\ndecouples submission from execution.",[45,477,479],{"className":47,"code":478,"language":49,"meta":50,"style":50},"ExecutorService pool = Executors.newFixedThreadPool(4);\nFuture\u003CInteger> f = pool.submit(() -> compute());\nInteger result = f.get();   \u002F\u002F blocks until done\npool.shutdown();            \u002F\u002F graceful: finish queued tasks\n",[26,480,481,501,531,550],{"__ignoreMap":50},[54,482,483,486,488,491,494,496,499],{"class":56,"line":57},[54,484,485],{"class":60},"ExecutorService pool ",[54,487,65],{"class":64},[54,489,490],{"class":60}," Executors.",[54,492,493],{"class":77},"newFixedThreadPool",[54,495,81],{"class":60},[54,497,498],{"class":269},"4",[54,500,88],{"class":60},[54,502,503,506,509,512,514,517,520,523,525,528],{"class":56,"line":91},[54,504,505],{"class":60},"Future\u003C",[54,507,508],{"class":64},"Integer",[54,510,511],{"class":60},"> f ",[54,513,65],{"class":64},[54,515,516],{"class":60}," pool.",[54,518,519],{"class":77},"submit",[54,521,522],{"class":60},"(() ",[54,524,71],{"class":64},[54,526,527],{"class":77}," compute",[54,529,530],{"class":60},"());\n",[54,532,533,536,538,541,544,547],{"class":56,"line":172},[54,534,535],{"class":60},"Integer result ",[54,537,65],{"class":64},[54,539,540],{"class":60}," f.",[54,542,543],{"class":77},"get",[54,545,546],{"class":60},"();   ",[54,548,549],{"class":193},"\u002F\u002F blocks until done\n",[54,551,552,555,558,561],{"class":56,"line":197},[54,553,554],{"class":60},"pool.",[54,556,557],{"class":77},"shutdown",[54,559,560],{"class":60},"();            ",[54,562,563],{"class":193},"\u002F\u002F graceful: finish queued tasks\n",[15,565,566,570,571,576,577,582,583,586,587,590,591,596],{},[38,567,568],{},[26,569,32],{}," returns nothing; ",[38,572,573],{},[26,574,575],{},"Callable\u003CV>"," returns a value and can throw;\n",[38,578,579],{},[26,580,581],{},"Future\u003CV>"," is a handle whose ",[26,584,585],{},"get()"," blocks for the result. Because ",[26,588,589],{},"Future.get()","\nblocks, prefer ",[38,592,593],{},[26,594,595],{},"CompletableFuture"," for non-blocking composition:",[45,598,600],{"className":47,"code":599,"language":49,"meta":50,"style":50},"CompletableFuture.supplyAsync(() -> fetchUser(id))\n    .thenApply(User::name)\n    .exceptionally(ex -> \"fallback\")\n    .thenAccept(System.out::println);\n",[26,601,602,620,637,655],{"__ignoreMap":50},[54,603,604,607,610,612,614,617],{"class":56,"line":57},[54,605,606],{"class":60},"CompletableFuture.",[54,608,609],{"class":77},"supplyAsync",[54,611,522],{"class":60},[54,613,71],{"class":64},[54,615,616],{"class":77}," fetchUser",[54,618,619],{"class":60},"(id))\n",[54,621,622,625,628,631,634],{"class":56,"line":91},[54,623,624],{"class":60},"    .",[54,626,627],{"class":77},"thenApply",[54,629,630],{"class":60},"(User",[54,632,633],{"class":64},"::",[54,635,636],{"class":60},"name)\n",[54,638,639,641,644,647,649,652],{"class":56,"line":172},[54,640,624],{"class":60},[54,642,643],{"class":77},"exceptionally",[54,645,646],{"class":60},"(ex ",[54,648,71],{"class":64},[54,650,651],{"class":84}," \"fallback\"",[54,653,654],{"class":60},")\n",[54,656,657,659,662,665,667],{"class":56,"line":197},[54,658,624],{"class":60},[54,660,661],{"class":77},"thenAccept",[54,663,664],{"class":60},"(System.out",[54,666,633],{"class":64},[54,668,669],{"class":60},"println);\n",[15,671,672,673,676,677,680,681,684],{},"Always shut a pool down (",[26,674,675],{},"shutdown()"," then ",[26,678,679],{},"awaitTermination",", falling back to\n",[26,682,683],{},"shutdownNow()",") — its non-daemon threads otherwise keep the JVM alive.",[10,686,688],{"id":687},"lock-free-tools-atomics-and-cas","Lock-free tools: atomics and CAS",[15,690,691,692,695,696,699,700,703,704,707,708,711,712,714],{},"The ",[26,693,694],{},"java.util.concurrent.atomic"," classes (",[26,697,698],{},"AtomicInteger",", ",[26,701,702],{},"AtomicReference",", …) provide\nthread-safe variables ",[38,705,706],{},"without locking",", using ",[38,709,710],{},"compare-and-swap (CAS)"," — \"if the\nvalue is still what I expect, replace it atomically.\" They outperform ",[26,713,207],{}," for\nsimple counters under contention.",[45,716,718],{"className":47,"code":717,"language":49,"meta":50,"style":50},"AtomicInteger count = new AtomicInteger();\ncount.incrementAndGet();         \u002F\u002F atomic, lock-free\ncount.compareAndSet(5, 10);      \u002F\u002F set to 10 only if currently 5\n",[26,719,720,734,748],{"__ignoreMap":50},[54,721,722,725,727,729,732],{"class":56,"line":57},[54,723,724],{"class":60},"AtomicInteger count ",[54,726,65],{"class":64},[54,728,399],{"class":64},[54,730,731],{"class":77}," AtomicInteger",[54,733,106],{"class":60},[54,735,736,739,742,745],{"class":56,"line":91},[54,737,738],{"class":60},"count.",[54,740,741],{"class":77},"incrementAndGet",[54,743,744],{"class":60},"();         ",[54,746,747],{"class":193},"\u002F\u002F atomic, lock-free\n",[54,749,750,752,755,757,760,762,765,768],{"class":56,"line":172},[54,751,738],{"class":60},[54,753,754],{"class":77},"compareAndSet",[54,756,81],{"class":60},[54,758,759],{"class":269},"5",[54,761,699],{"class":60},[54,763,764],{"class":269},"10",[54,766,767],{"class":60},");      ",[54,769,770],{"class":193},"\u002F\u002F set to 10 only if currently 5\n",[15,772,773,774,779,780,783],{},"CAS is the basis of lock-free algorithms (no deadlock, better scalability), though it can\nspin under contention. For thread-confined state, ",[38,775,776],{},[26,777,778],{},"ThreadLocal"," gives each thread its\nown copy — just remember to ",[26,781,782],{},"remove()"," it in thread pools to avoid leaks.",[10,785,787],{"id":786},"the-java-memory-model","The Java Memory Model",[15,789,790,791,794,795,797,798,800,801,804,805,127],{},"The JMM defines ",[38,792,793],{},"when one thread's writes become visible to another",", via the\n",[38,796,215],{}," relationship. Key edges: unlocking a monitor -> subsequently locking it;\na ",[26,799,240],{}," write -> a subsequent read; ",[26,802,803],{},"Thread.start"," -> the thread's actions; a thread's\nactions -> another's ",[26,806,807],{},"join",[45,809,811],{"className":47,"code":810,"language":49,"meta":50,"style":50},"volatile boolean ready;\nint data;\n\u002F\u002F Thread A: data = 42; ready = true;        \u002F\u002F volatile write publishes data\n\u002F\u002F Thread B: if (ready) use(data);           \u002F\u002F sees 42 — happens-before guarantees it\n",[26,812,813,822,830,838],{"__ignoreMap":50},[54,814,815,817,819],{"class":56,"line":57},[54,816,240],{"class":64},[54,818,261],{"class":64},[54,820,821],{"class":60}," ready;\n",[54,823,824,827],{"class":56,"line":91},[54,825,826],{"class":64},"int",[54,828,829],{"class":60}," data;\n",[54,831,832,835],{"class":56,"line":172},[54,833,834],{"class":193},"\u002F\u002F Thread A: data = 42; ready = true;",[54,836,837],{"class":193},"        \u002F\u002F volatile write publishes data\n",[54,839,840,843],{"class":56,"line":197},[54,841,842],{"class":193},"\u002F\u002F Thread B: if (ready) use(data);",[54,844,845],{"class":193},"           \u002F\u002F sees 42 — happens-before guarantees it\n",[15,847,848,849,852,853,856,857,360,859,861,862,865,866,868],{},"Without a happens-before relationship, a thread may ",[38,850,851],{},"never"," see another's writes — which\nis ",[226,854,855],{},"why"," ",[26,858,240],{},[26,860,207],{}," exist. The classic ",[38,863,864],{},"double-checked locking"," singleton\nneeds a ",[26,867,240],{}," field precisely to prevent publishing a partially-constructed object.",[10,870,872],{"id":871},"recap","Recap",[15,874,875,876,879,880,882,883,699,886,888,889,893,894,898,899,902,903,906,907,909,910,913,914,917,918,920,921,360,924,927],{},"Java concurrency starts with ",[38,877,878],{},"threads"," (prefer ",[26,881,32],{},") and the hazards of shared\nmutable state — ",[38,884,885],{},"race conditions",[38,887,322],{},", visibility bugs. ",[38,890,891],{},[26,892,207],{},"\ngives mutual exclusion plus visibility; ",[38,895,896],{},[26,897,240],{}," gives visibility only;\n",[38,900,901],{},"atomics\u002FCAS"," give lock-free updates. Build on the high-level toolkit — ",[38,904,905],{},"executors"," and\n",[26,908,595],{}," for running tasks, ",[38,911,912],{},"BlockingQueue","\u002Flatches\u002Fbarriers for coordination,\n",[38,915,916],{},"concurrent collections"," for shared data — and reason about correctness through\n",[38,919,215],{}," in the memory model. Lean on those abstractions over raw threads and\n",[26,922,923],{},"wait",[26,925,926],{},"notify",", and concurrent Java becomes manageable.",[929,930,931],"style",{},"html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}",{"title":50,"searchDepth":91,"depth":91,"links":933},[934,935,936,937,938,939,940,941,942,943],{"id":12,"depth":91,"text":13},{"id":20,"depth":91,"text":21},{"id":130,"depth":91,"text":131},{"id":232,"depth":91,"text":233},{"id":316,"depth":91,"text":317},{"id":353,"depth":91,"text":354},{"id":464,"depth":91,"text":465},{"id":687,"depth":91,"text":688},{"id":786,"depth":91,"text":787},{"id":871,"depth":91,"text":872},"Java concurrency interview questions — threads vs Runnable, synchronized, volatile, the memory model, deadlock, wait\u002Fnotify, executors, futures, CompletableFuture and atomic classes.","hard","md","Java",{},true,"\u002Fblog\u002Fjava-concurrency-threads-synchronization","\u002Fjava\u002Fconcurrency\u002Fthreads",{"title":5,"description":944},"blog\u002Fjava-concurrency-threads-synchronization","Threads & Synchronization","Concurrency","concurrency","2026-06-18","4BzEbYaBxdTIfCDCGETbRcjrSuR4_WxebbH0j7KpP4U",1781808673081]