JiwonDev

์“ฐ๋ ˆ๋“œ ๋™๊ธฐํ™” (sync, volatile, AtomicClass)

by JiwonDev

์“ฐ๋ ˆ๋“œ์˜ ๋™๊ธฐํ™” : ํ•œ ์“ฐ๋ ˆ๋“œ๊ฐ€ ์ง„ํ–‰์ค‘์ธ ์ž‘์—…์„ ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๊ฐ„์„œํ•˜์ง€ ๋ชปํ•˜๊ฒŒ ํ•˜๋Š” ๊ฒƒ.

 

์“ฐ๋ ˆ๋“œ๋Š” class์˜ ๋ฉค๋ฒ„ ๋ณ€์ˆ˜(์ž์›)์„ ์‚ฌ์šฉํ•œ๋‹ค. ๋ฉ€ํ‹ฐ์“ฐ๋ ˆ๋“œ ํ™˜๊ฒฝ์—์„œ๋Š” ์“ฐ๋ ˆ๋“œ ๋™๊ธฐํ™”๋ฅผ ํ•˜์ง€์•Š์œผ๋ฉด, ์‹ฌ๊ฐํ•œ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธธ ์ˆ˜ ์žˆ๋‹ค.

์ด๋Ÿฐ ์ƒํ™ฉ์ด ์žˆ์„ ๋•Œ, ๋™๊ธฐํ™”ํ•˜์ง€ ์•Š์œผ๋ฉด ์‹ฌ๊ฐํ•œ ๋ฌธ์ œ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

 

#์ž๋ฐ”์˜ synchronized ํ‚ค์›Œ๋“œ

์ž๋ฐ”๋Š” synchronized ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•ด๋‹น ๋ฉ”์„œ๋“œ๋ฅผ ์ž„๊ณ„์˜์—ญ์œผ๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค€๋‹ค. ์ž„๊ณ„์˜์—ญ์—์„œ๋Š” ๋™์‹œ์— ํ•œ ์“ฐ๋ ˆ๋“œ๋งŒ ์ ‘๊ทผํ•ด์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๋‹ค๋ฅธ์“ฐ๋ ˆ๋“œ์˜ ์ ‘๊ทผ์„ ๋ง‰๋Š”๋‹ค(lock) 

  • synchronized ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
  • synchronized block์„ ๋งŒ๋“ค์–ด ์ผ๋ถ€๋งŒ ๋™๊ธฐํ™”์ฒ˜๋ฆฌํ•œ๋‹ค. (์„ฑ๋Šฅ ํ–ฅ์ƒ์„ ์œ„ํ•จ)
public synchronized void method() {
	// ์ž„๊ณ„์˜์—ญ
}

public void function() {
    synchronized(๊ฐ์ฒด์˜ ์ฐธ์กฐ๋ณ€์ˆ˜) {
        // ์ž„๊ณ„์˜์—ญ
    }
}

synchronzied๋Š” ๋‹ค์ˆ˜์˜ ์“ฐ๋ ˆ๋“œ์—๊ฒŒ ๊ณต์œ ๋˜๋Š” ๊ฐ์ฒด ์ ‘๊ทผ์„ ํ†ต์ œํ•˜๋Š” ์ž๋ฐ”์˜ ์ฒซ๋ฒˆ์งธ ๋™๊ธฐํ™” ๋ฉ”์นด๋‹ˆ์ฆ˜์ด์—ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด๊ฒƒ๋งŒ์œผ๋กœ๋Š” ๋‹ค์–‘ํ•œ ์ƒํ™ฉ์— ๋Œ€์ฒ˜ํ•˜๊ธฐ ํž˜๋“ค์—ˆ๊ธฐ์— Java5 ์— Concurrent ๊ด€๋ จ ํด๋ž˜์Šค๋“ค์„ ์ถ”๊ฐ€ํ•˜์˜€๋‹ค.


# Atomic ํด๋ž˜์Šค (java.concurrent.atomic)

ํ‚ค์›Œ๋“œ ๋ง๊ณ ๋„ ์ž๋ฐ”์—์„œ๋Š” CAS(compare and swap) ๋ฐฉ์‹์œผ๋กœ ์Šค๋ ˆ๋“œ ์•ˆ์ •์„ฑ์„ ๋ณด์žฅํ•˜๋Š” Atomic ํŒจํ‚ค์ง€๋ฅผ ์ œ๊ณตํ•œ๋‹ค.

import java.util.concurrent.atomic.AtomicInteger;

private AtomicInteger counter = new AtomicInteger();

public int getNextUniqueIndex() {
    return counter.getAndIncrement();
}

CAS ๋ฐฉ์‹์€ ์ž์‹ ์ด ์ฝ์—ˆ๋˜ ๋ณ€์ˆ˜์˜ ๊ฐ’์„ ๊ธฐ์–ตํ•˜๊ณ  ์žˆ๋‹ค๊ฐ€ ๋ณ€๊ฒฝ์„ ์™„๋ฃŒํ•˜๊ธฐ ์ง์ „์— ์ฝ์—ˆ๋˜ ๋ณ€์ˆ˜์˜ ๊ฐ’์ด ๊ทธ๋Œ€๋กœ์ธ์ง€ ํ™•์ธํ•˜๊ณ  ์•„๋‹ˆ๋ผ๋ฉด ์‹คํ–‰์„ ๋ฌด์‚ฐ์‹œํ‚ค๋Š” ๋ฐฉ์‹์ด๋‹ค.

 

 // C์–ธ์–ด๋กœ ๊ตฌํ˜„ํ•œ CAS
 int compare_and_swap(int* reg, int oldval, int newval){ 
 // ๋ณ€๊ฒฝ์ „ ๊ฐ’์„ ์ €์žฅํ•ด๋’€๋‹ค๊ฐ€, ํŽธ์ง‘ ์™„๋ฃŒ ํ›„์—๋„ ๋ฉ”๋ชจ๋ฆฌ์— ๊ธฐ์กด ๊ฐ’์ด ๋‚จ์•„์žˆ์–ด์•ผ swapํ•˜๋Š” ๋ฐฉ์‹.
    int old_reg_val = *reg;
    if (old_reg_val == oldval){
        *reg = newval;
    }
     return old_reg_val;
}

 


# volatile (๋ณผ๋ผํ‹ธ) ํ‚ค์›Œ๋“œ

volatile ํ‚ค์›Œ๋“œ๋Š” ์ž๋ฐ” ๋ณ€์ˆ˜๋ฅผ CPU ์บ์‹œ๊ฐ€ ์•„๋‹Œ '๋ฉ”์ธ ๋ฉ”๋ชจ๋ฆฌ์— ์ €์žฅ'ํ•  ๊ฒƒ์„ ๋ช…์‹œํ•ด ๋ณ€์ˆ˜์˜ ๊ฐ€์‹œ์„ฑ์„ ๋ณด์žฅํ•œ๋‹ค.

 

์ฆ‰ volatile์€ ๋ณ€์ˆ˜์˜ ์ฝ๊ธฐ/์“ฐ๊ธฐ ๋ช…๋ น์„ ๋ฉ”์ธ ๋ฉ”๋ชจ๋ฆฌ๋กœ๋ถ€ํ„ฐ ์ˆ˜ํ–‰ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ๋ณด์žฅํ•œ๋‹ค. ์ด๋Š” ์ฝ๊ธฐ ์Šค๋ ˆ๋“œ์™€ ์“ฐ๊ธฐ ์Šค๋ ˆ๋“œ๊ฐ€ ํ•จ๊ป˜ ๋™์ž‘ํ–ˆ์„ ๋•Œ ์ผ์–ด๋‚˜๋Š” ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค

 


@ ์™œ ์ฝ๊ธฐ / ์“ฐ๊ธฐ๋ฅผ ๊ฐ™์ดํ•˜๋ฉด ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธฐ๋Š” ๊ฑธ๊นŒ?

CPU์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์„ ๋•Œ, ์„ฑ๋Šฅ์„ ํ–ฅ์ƒ์‹œํ‚ค๊ธฐ ์œ„ํ•ด Main Memory์—์„œ ๊ณ„์† ์ฝ๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ๊ฐ CPU ์ฝ”์–ด์˜ ์บ์‹œ์— ์ €์žฅํ•˜์—ฌ ์‚ฌ์šฉํ•œ๋‹ค. ๊ทธ๋ ‡๋‹ค๋ฉด ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์•ฑ์—์„œ, CPU ์ฝ”์–ด๊ฐ€ ์—ฌ๋Ÿฌ๊ฐœ๋ผ๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ?

์ด๋ ‡๊ฒŒ ์ผ๋ฐ˜ ๋ณ€์ˆ˜(non-volatile)์— ๋Œ€ํ•œ ์ž‘์—…์€ JVM์ด ๋ฉ”์ธ ๋ฉ”๋ชจ๋ฆฌ๋กœ๋ถ€ํ„ฐ CPU ์บ์‹œ๋ฅผ ํ†ตํ•ด ๋ณ€์ˆ˜๋ฅผ ์ฝ๊ฑฐ๋‚˜ ๋ฐ˜๋Œ€๋กœ CPU ์บ์‹œ๋กœ ๋ถ€ํ„ฐ ๋ฉ”์ธ ๋ฉ”๋ชจ๋ฆฌ์— ๋ฐ์ดํ„ฐ๋ฅผ ์“ฐ๊ฑฐ๋‚˜ ํ•  ๋•Œ ์–ด๋– ํ•œ ๋™๊ธฐํ™” ๋ณด์žฅ๋„ ํ•ด์ฃผ์ง€ ์•Š๋Š”๋‹ค.

 

์˜ˆ๋ฅผ ๋“ค์–ด ๋‘˜ ์ด์ƒ์˜ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ณต์œ  ๊ฐ์ฒด๋กœ ์ ‘๊ทผํ•˜๋Š” ๊ฒฝ์šฐ๋ฅผ ์ƒ๊ฐํ•ด๋ณด์ž.

// Thread-1 : counter ๋ณ€์ˆ˜๋ฅผ ์ˆ˜์ •ํ•จ. (+1์”ฉ ์ฆ๊ฐ€์‹œํ‚ด)
// Thread-2 : counter ๋ณ€์ˆ˜๋ฅผ ์ฝ์Œ

public class SharedObject {
    public int counter = 0;
}

๋งŒ์•ฝ volatile ํ‚ค์›Œ๋“œ๋ฅผ ์„ ์–ธํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด, counter ๋ณ€์ˆ˜๊ฐ€ ์–ธ์ œ CPU ์บ์‹œ์—์„œ ๋ฉ”์ธ๋ฉ”๋ชจ๋ฆฌ๋กœ ์ด๋™๋ ์ง€ ๋ณด์žฅํ•  ์ˆ˜ ์—†๋‹ค. ์ฆ‰ ๋ฉ€ํ‹ฐ์ฝ”์–ด CPU์˜ ๊ฒฝ์šฐ ๊ฐ™์€ ๋ณ€์ˆ˜์ž„์—๋„ ๋‹ค๋ฅธ ๊ฐ’์„ ๊ฐ€์ง€๊ณ  ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค๋Š” ๋ง์ด๋‹ค. ์ด๋ ‡๊ฒŒ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๋ณ€๊ฒฝํ•œ ๊ฐ’์ด ๋ฉ”์ธ ๋ฉ”๋ชจ๋ฆฌ์— ๋ฐ˜์˜๋˜์ง€ ์•Š์•„ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๊ฐ€ ํ•ด๋‹น ๊ฐ’์„ ๋ณผ ์ˆ˜ ์—†๋Š” ๋ฌธ์ œ๋ฅผ '๊ฐ€์‹œ์„ฑ ๋ฌธ์ œ' ๋ผ๊ณ  ํ•œ๋‹ค.

์—ฌ๊ธฐ์—์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด volatile ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๊ฒŒ๋œ๋‹ค๋ฉด ํ•ด๋‹น ๋ณ€์ˆ˜์— ๋Œ€ํ•œ ์“ฐ๊ธฐ ์ž‘์—…์€ ์บ์‹œ์—†์ด ๋ฐ”๋กœ ๋ฉ”์ธ ๋ฉ”๋ชจ๋ฆฌ์— ์ด๋ฃจ์–ด์ง„๋‹ค. ์ฆ‰ ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ์˜ ์“ฐ๊ธฐ ์ž‘์—…์— ๋Œ€ํ•œ ๊ฐ€์‹œ์„ฑ์„ ๋ณด์žฅํ•œ๋‹ค.

 


@ JDK1.5 ์ดํ›„์˜ volatile

์ฐธ๊ณ ๋กœ JDK1.5 ๋ถ€ํ„ฐ๋Š” volatile ํ‚ค์›Œ๋“œ๋Š” ๋‹จ์ˆœํžˆ ๊ฐ€์‹œ์„ฑ์„ ๋ณด์žฅํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ๋” ๋งŽ์€ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๋„๋ก ๋ฐ”๋€Œ์—ˆ๋‹ค.

https://parkcheolu.tistory.com/16

 

์ž๋ฐ” volatile ํ‚ค์›Œ๋“œ

์ด ๊ธ€์€ ์› ์ €์ž Jakob Jenkov์˜ ํ—ˆ๊ฐ€๋กœ ํฌ์ŠคํŒ…๋œ ๋ฒˆ์—ญ๋ฌผ์ด๋‹ค. ์›๋ฌธ URL : http://tutorials.jenkov.com/java-concurrency/volatile.html  ์ž๋ฐ” volatile ํ‚ค์›Œ๋“œ๋Š” ์ž๋ฐ” ์ฝ”๋“œ์˜ ๋ณ€์ˆ˜๋ฅผ '๋ฉ”์ธ ๋ฉ”๋ชจ๋ฆฌ์— ์ €์žฅ' ํ• ..

parkcheolu.tistory.com

 

  • volatile ๋ณ€์ˆ˜๋ฅผ ์ˆ˜์ • ํ•  ๋•Œ ํ˜„์žฌ๊นŒ์ง€ ์ˆ˜์ •ํ•œ ๋ชจ๋“  ๋ณ€์ˆ˜๋“ค์ด ๋ฉ”์ธ๋ฉ”๋ชจ๋ฆฌ์— ์ €์žฅ(flushed)๋œ๋‹ค.
  • volatile ๋ณ€์ˆ˜๋ฅผ ์บ์‹œ๋กœ ์ฝ์–ด๋“ค์ผ ๋•Œ ์•ž์—์„œ ๊ฐ™์ด ์ €์žฅํ•œ ๋ณ€์ˆ˜๋“ค๋„ ๊ฐ™์ด ์ฝ๋Š”๋‹ค.

 


@ ๊ทธ๋Ÿผ volatile์ด ๋ฌด์กฐ๊ฑด ์ข‹์€๊ฑด๊ฐ€์š”?

volatile์€ ํ•œ ๋ณ€์ˆ˜๋ฅผ ๋‘๊ณ  ์˜ค์ง ํ•œ ์“ฐ๋ ˆ๋“œ๋งŒ ์ฝ๊ธฐ/์“ฐ๊ธฐ ์ž‘์—…์„ ํ•˜๊ณ , ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ๋“ค์€ ์ฝ๊ธฐ ์ž‘์—…๋งŒ ํ•œ๋‹ค๋ฉด ์‚ฌ์šฉํ–ˆ์„ ๋•Œ ๋…ผ๋ธ”๋กœํ‚น ๋ฉ€ํ‹ฐ์“ฐ๋ ˆ๋“œ๋ฅผ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด ๊ฒฝ์šฐ๊ฐ€ ์•„๋‹ˆ๋ผ๋ฉด ๋ง์ด ๋‹ฌ๋ผ์ง„๋‹ค.

 

volatile ์„ ์–ธ์€ ๋ณ€์ˆ˜์— ์ ‘๊ทผํ•˜๋Š” ์“ฐ๋ ˆ๋“œ๋“ค์„ ๋ธ”๋ก์‹œํ‚ค์ง€ ์•Š๋Š”๋‹ค. ๊ทธ๋ž˜์„œ ๊ณต์œ  ๋ณ€์ˆ˜๋ฅผ ์—ฌ๋Ÿฌ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๋™์‹œ์— ์“ฐ๋Š”(write) ์ž„๊ณ„์˜์—ญ์— ๋Œ€ํ•ด์„œ ๋ช…๋ น์ด ๋ฌด์‹œ๋  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋‹ค. ์ฆ‰ ํ•ด๋‹น ๋ช…๋ น์˜ ์›์ž์„ฑ์„ ๋ณด์žฅ์„ ๋ณด์žฅํ•˜์ง€ ์•Š๋Š”๋ฐ, ์ด๋Ÿฐ ๊ฒฝ์šฐ์—๋Š” synchronized ํ‚ค์›Œ๋“œ๊ฐ€ ํ•„์š”ํ•˜๋‹ค. ๋งŒ์•ฝ synchrozined ๋กœ ๊ธฐ๋Šฅ์ด ๋ถ€์กฑํ•˜๋‹ค๋ฉด ์œ„์—์„œ ์–ธ๊ธ‰ํ•œ java.util.concurrent์— ์žˆ๋Š” Atomic ํด๋ž˜์Šค๋“ค์„ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค. 

 

๋˜ํ•œ volatile ๋•Œ๋ฌธ์— CPU ์บ์‹œ๋ฅผ ์“ฐ์ง€ ๋ชปํ•ด์„œ ์„ฑ๋Šฅ์ด ๋–จ์–ด์งˆ ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๊ณ , JVM์˜ ์ฝ”๋“œ ์žฌ์ •๋ฆฌ, ์ตœ์ ํ™”๋„ ํ•ด๋‹น ํ‚ค์›Œ๋“œ ๋•Œ๋ฌธ์— ๋™์ž‘ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Œ์„ ์œ ์˜ํ•˜์ž.

 

 

๋ธ”๋กœ๊ทธ์˜ ์ •๋ณด

JiwonDev

JiwonDev

ํ™œ๋™ํ•˜๊ธฐ