[Java] synchronized์™€ Lock

Java์—์„œ Lock์„ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•๊ณผ ๊ทธ ์ข…๋ฅ˜์— ๋Œ€ํ•ด ์ •๋ฆฌํ•ด๋ณธ๋‹ค.




๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ์™€ Data Race ๋ฌธ์ œ

Lock๋Š” ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ํ™˜๊ฒฝ์—์„œ ๋ฐœ์ƒํ•˜๋Š” ๋Œ€ํ‘œ์ ์ธ ๋ถ€์ž‘์šฉ์ธ ๋™์‹œ์„ฑ ์“ฐ๊ธฐ, Data race ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ์กด์žฌํ•œ๋‹ค. ์ด ๋ฌธ์ œ์— ๋Œ€ํ•ด ์•ˆ๋‹ค๋ฉด ๋ฌด์‹œํ•˜๊ณ  ๋„˜์–ด๊ฐ€๋„ ๋œ๋‹ค.

package org.example;

class SharedObject {
    public int count = 0;
}

public class Main {
    public static void main(String[] args) {
         var shared = new SharedObject();

        // ์Šค๋ ˆ๋“œ๋ฅผ 5๊ฐœ ์ƒ์„ฑํ•ด์„œ count๋ฅผ ์ฆ๊ฐ€์‹œํ‚ด
        for (int i = 0; i < 5; i++) {
            Thread thread = new Thread(() -> {
                for (int j = 0; j < 1000; j++) {
                    shared.count++;
                }
            });
            thread.start();
        }

        // ๋ชจ๋“  ์Šค๋ ˆ๋“œ๊ฐ€ ์ข…๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ๋Œ€๊ธฐ
        while (Thread.activeCount() > 1) {
            Thread.yield();
        }

        System.out.println(shared.count);
    }
}

์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด, ์Šค๋ ˆ๋“œ๋ฅผ 5๊ฐœ ๋„์šฐ๊ณ  ๊ณต์œ  ์ž์›์— ๋Œ€ํ•ด์„œ ๊ณ„์†ํ•ด์„œ +1 ์—ฐ์‚ฐ์„ ๊ฐ€ํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.
์Šค๋ ˆ๋“œ 5๊ฐœ์—์„œ 1000๋ฒˆ์”ฉ ์ฆ๊ฐ€ ์—ฐ์‚ฐ์„ ๋•Œ๋ฆฌ๋‹ˆ, ์ผ๋ฐ˜์ ์œผ๋กœ๋Š” ์ตœ์ข… ๊ฒฐ๊ณผ๊ฐ’์ด 5000์ด ๋  ๊ฒƒ์ด๋ผ๊ณ  ๊ธฐ๋Œ€ํ•  ์ˆ˜ ์žˆ๋‹ค.


ํ•˜์ง€๋งŒ ์‹ค์ œ ๊ฒฐ๊ณผ๋Š” ๊ทธ๋ ‡์ง€ ์•Š๋‹ค.

์—ฌ๋Ÿฌ๊ฐœ์˜ ์Šค๋ ˆ๋“œ์—์„œ n+1 ์—ฐ์‚ฐ์„ ๊ฐ€ํ•˜๋Š”๋ฐ, ๊ทธ๊ฒŒ ๋™์‹œ์— ์ค‘์ฒฉ๋œ๋‹ค๋ฉด 2๊ฐœ ์ด์ƒ์˜ ์Šค๋ ˆ๋“œ์—์„œ ๋™์ผํ•œ ๊ฐ’์„ ์“ฐ๋ฉด์„œ ํ•˜๋‚˜๋ฅผ ์ œ์™ธํ•œ ์Šค๋ ˆ๋“œ์˜ write๊ฐ€ ๋ฒ„๋ ค์งˆ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

๋ฌผ๋ก  ์ด๊ฑด ์•„์ฃผ ๋‹จ์ˆœํ•œ ๊ฒฝ์šฐ๊ณ , ์‹ค์ œ ํ”„๋กœ๊ทธ๋žจ์—์„œ ๋™์‹œ์„ฑ ๋ฌธ์ œ๋Š” ๋ณดํ†ต ์ข€ ๋” ๋ณต์žกํ•œ ํ˜•ํƒœ๋กœ ๋“œ๋Ÿฌ๋‚œ๋‹ค.

์•„๋ฌดํŠผ ์—ฌ๊ธฐ์„œ ์ค‘์š”ํ•œ ๊ฒƒ์€, ์—ฌ๋Ÿฌ๊ฐœ์˜ ์Šค๋ ˆ๋“œ์—์„œ "๋™์‹œ์— ์“ฐ๋Š” ํ–‰์œ„" ์ž์ฒด๊ฐ€ ๋งค์šฐ ์œ„ํ—˜ํ•˜๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.




synchronized๋ฅผ ์ด์šฉํ•œ Lock

Java๋Š” ๋“œ๋ฌผ๊ฒŒ ๋™๊ธฐํ™”์— ๋Œ€ํ•œ ์ง€์›์„ ์–ธ์–ด ์‹ ํƒ์Šค๋ถ€ํ„ฐ ์ง€์›ํ•˜๋Š” ์–ธ์–ด๋‹ค.
synchronized ํ‚ค์›Œ๋“œ๋ฅผ ๋ฉ”์„œ๋“œ์— ๋ถ™์ด๋ฉด, ๊ทธ ๋ฉ”์„œ๋“œ๋Š” ์™„๋ฒฝํ•˜๊ฒŒ ๋™๊ธฐํ™”๋˜๋Š” ๋ฉ”์„œ๋“œ๊ฐ€ ๋œ๋‹ค.

๋™์ผํ•œ ๊ฐ์ฒด์— ๋Œ€ํ•ด์„œ ์ € ๋ฉ”์„œ๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด, ์ € ๋ฉ”์„œ๋“œ ์ž์ฒด๋Š” ๋™์‹œ์— ํ•˜๋‚˜์”ฉ๋งŒ ์ˆ˜ํ–‰๋˜๋Š” ๊ฒƒ์ด ๋ณด์žฅ๋œ๋‹ค.

์ข€ ๋” ์›๋ฆฌ๋ฅผ ์ž์„ธํ•˜๊ฒŒ ์„ค๋ช…ํ•˜์ž๋ฉด, ๋ฉ”์„œ๋“œ๊ฐ€ ์‹œ์ž‘๋ ๋•Œ ์ € ๊ฐ์ฒด(this)๋ฅผ ๊ธฐ์ค€์œผ๋กœ Mutex.lock์„ ๊ฑธ๊ณ , ๋ฉ”์„œ๋“œ๊ฐ€ ๋๋‚˜๋ฉด Mutex.unlock์„ ๊ฑฐ๋Š” ๊ฒƒ์ด๋‹ค.

๊ทธ๋ ‡๊ฒŒ ๋™๊ธฐํ™”๋œ ๋ฉ”์„œ๋“œ๋ฅผ ๋งŒ๋“ค๊ณ  ๊ทธ๊ฑธ๋กœ ๋Œ€์ฒดํ•˜๋ฉด

๊ธฐ๋Œ€ํ•œ ๋Œ€๋กœ ์ถฉ๋Œ์€ ๋” ์ด์ƒ ๋ฐœ์ƒํ•˜์ง€ ์•Š์„ ๊ฒƒ์ด๋‹ค.


package org.example;

class SharedObject {
    public int count = 0;

    // synchronized ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฉ”์†Œ๋“œ ์ „์ฒด์— ๋ฝ์ด ๊ฑธ๋ฆผ
    public synchronized void increment() {
        count++;
    }
}

public class Main {
    public static void main(String[] args) {
         var shared = new SharedObject();

        // ์Šค๋ ˆ๋“œ๋ฅผ 5๊ฐœ ์ƒ์„ฑํ•ด์„œ count๋ฅผ ์ฆ๊ฐ€์‹œํ‚ด
        for (int i = 0; i < 5; i++) {
            Thread thread = new Thread(() -> {
                for (int j = 0; j < 1000; j++) {
                    shared.increment();
                }
            });
            thread.start();
        }

        // ๋ชจ๋“  ์Šค๋ ˆ๋“œ๊ฐ€ ์ข…๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ๋Œ€๊ธฐ
        while (Thread.activeCount() > 1) {
            Thread.yield();
        }

        System.out.println(shared.count);
    }
}



synchronized ๋ธ”๋Ÿญ์„ ํ†ตํ•œ ๋™๊ธฐํ™”

์ด๊ฒƒ๋„ synchronized ๋ฉ”์„œ๋“œ์™€ ๋™์ž‘๋ฐฉ์‹์€ ๊ฑฐ์˜ ๋™์ผํ•˜๋‹ค.
๊ทธ ๋ฒ”์œ„๊ฐ€ ๋ฉ”์„œ๋“œ ๋ฒ”์œ„์—์„œ ๋ธ”๋ก ๋ฒ”์œ„๋กœ ์ขํ˜€์ง„ ๊ฒƒ์ผ ๋ฟ์ด๋‹ค.

๋ฉ”์„œ๋“œ๊ฐ€ ๊ธธ๊ณ , ๋ฝ์„ ์žก์•„์•ผํ•  ๋ฒ”์œ„๊ฐ€ ํ•œ์ •์ ์ด๋ผ๋ฉด ๋ฉ”์„œ๋“œ ์ „์ฒด์— ๋Œ€ํ•ด์„œ ๊ฑฐ๋Š” ๊ฒƒ์€ ์ฒ˜๋ฆฌ๋Ÿ‰์„ ๋–จ์–ด๋œจ๋ฆฌ๋Š” ์ง“์ด๊ธฐ ๋•Œ๋ฌธ์—, ๋ฝ์„ ๊ฑธ์–ด์•ผํ•  ๋ฒ”์œ„์— ๋Œ€ํ•ด์„œ๋งŒ ๊ฑธ์–ด์ฃผ๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

์‚ฌ์šฉ ๋ฐฉ๋ฒ•์€ ์–ด๋ ต์ง€ ์•Š๋‹ค.

์ด๋Ÿฐ ๋А๋‚Œ์œผ๋กœ lock ๋ธ”๋Ÿญ์„ ์žก๊ณ  ๊ทธ ์•ˆ์—์„œ๋งŒ ๋™์‹œ์„ฑ ์“ฐ๊ธฐ๋ฅผ ํ•˜๋ฉด ๋œ๋‹ค.
์†Œ๊ด„ํ˜ธ์— ๋“ค์–ด๊ฐ€๋Š” ์ธ์ž๊ฐ€ lock์„ ์žก๋Š” ๊ธฐ์ค€๊ฐ’์ธ๋ฐ, ๋ณดํ†ต this๋ฅผ ๋„ฃ์–ด์„œ ์ € ๊ฐ์ฒด ์ž์ฒด์— ๋Œ€ํ•ด์„œ๋งŒ ๋ณด์žฅํ•œ๋‹ค. ์• ์ดˆ์— synchronized method๋„ synchronized(this)๊ฐ€ ๋‚ด๋ถ€ ๋™์ž‘์ด๋‹ค.




synchronized์˜ ๋ฌธ์ œ

synchronized๊ฐ€ ๊ฐ„๋‹จํ•˜๊ณ  ์‚ฌ์šฉ์ด ํŽธ๋ฆฌํ•˜๊ธด ํ•˜์ง€๋งŒ, ๋‹จ์ ๋„ ๋งŽ๋‹ค.
์ด๊ฑด ์ •๋ง ์•„์ฃผ ๋‹จ์ˆœํ•œ ์‚ฌ์šฉ์‚ฌ๋ก€์—์„œ๋งŒ ์“ธ๋งŒํ•˜๊ณ , ์ตœ์ ํ™”๊ฐ€ ํ•„์š”ํ•œ ์˜์—ญ์—์„œ๋Š” ํ•œ๊ณ„๊ฐ€ ํฌ๋‹ค.

๊ฐ€์žฅ ํฐ ๋ฌธ์ œ๋Š” Lock์„ ์žก๋Š” ๋ฒ”์œ„๋ฅผ ์„ธ๋ฐ€ํ•˜๊ฒŒ ์กฐ์ ˆํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.
๊ทธ๋ž˜์„œ ํ•ด๋‹น ๊ฐ์ฒด์— ๋ณ„๊ฐœ์˜ ํ๋ฆ„์„ ๊ฐ–๋Š” ๋™๊ธฐํ™” ํฌ์ธํŠธ๊ฐ€ 2๊ฐœ ์ด์ƒ ์žˆ์„ ๊ฒฝ์šฐ์—๋Š” ์œ ์—ฐํ•˜๊ฒŒ ์ฒ˜๋ฆฌ๋ฅผ ํ•  ์ˆ˜๊ฐ€ ์—†๋‹ค.

๊ฒŒ๋‹ค๊ฐ€ ๋‹ค๋ฅธ Lock ๊ตฌํ˜„์ฒด๊ฐ€ ์ œ๊ณตํ•˜๋Š” lock ํƒ€์ž„์•„์›ƒ, ๊ณต์ •์„ฑ ์ฒ˜๋ฆฌ, ๋””๋ฒ„๊น… ์ˆ˜์ค€์—์„œ ๋ถ€์กฑํ•œ ๋ถ€๋ถ„์ด ๋งŽ๋‹ค.





ReentrantLock์„ ํ†ตํ•œ ๋ช…์‹œ์  Lock

ReentrantLock์€ Java์˜ ๋Œ€ํ‘œ์ ์ธ Lock ๊ตฌํ˜„์ฒด ์ค‘ ํ•˜๋‚˜๋‹ค.
์‰ฝ๊ฒŒ ๋งํ•˜๋ฉด ๊ทธ๋ƒฅ Mutex ๊ตฌํ˜„์ธ๋ฐ, ๊ทธ ์™ธ์—๋„ ์ž์ž˜ํ•œ ๊ธฐ๋Šฅ๋“ค์ด ์กฐ๊ธˆ ๋ถ™์–ด์žˆ๋‹ค.

ํ•œ๋ฒˆ ์„ฑ๋Šฅ๋น„๊ต๋ฅผ ํ•ด๋ณด๋ฉด์„œ ReentrantLock์ด ์ ์ ˆํ•œ ๊ฒฝ์šฐ๋ฅผ ์˜ˆ๋กœ ๋“ค์–ด๋ณด๊ฒ ๋‹ค.

์ด๋ฒˆ ๊ฐ์ฒด์—๋Š” 2๊ฐœ์˜ ๊ณต์œ  ๋ณ€์ˆ˜๊ฐ€ ์žˆ๊ณ , ๊ฐ๊ฐ์˜ ์ฆ๊ฐ€๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์—ˆ๋‹ค.


๊ทธ๋ฆฌ๊ณ  ์Šค๋ ˆ๋“œ ์ž”๋œฉ ๋„์›Œ์„œ ๋Œ๋ฆฌ๋ฉด,


package org.example;

class SharedObject {
    public int a_count = 0;
    public int b_count = 0;

    public synchronized void increment_a() {
        a_count++;
    }

    public synchronized void increment_b() {
        b_count++;
    }
}

public class Main {
    public static void main(String[] args) {
         var shared = new SharedObject();

         var start = System.currentTimeMillis();

        // ์Šค๋ ˆ๋“œ๋ฅผ 5๊ฐœ ์ƒ์„ฑํ•ด์„œ count๋ฅผ ์ฆ๊ฐ€์‹œํ‚ด
        for (int i = 0; i < 5; i++) {
            Thread thread = new Thread(() -> {
                for (int j = 0; j < 10000000; j++) {
                    shared.increment_a();
                    shared.increment_b();
                }
            });
            thread.start();
        }

        // ๋ชจ๋“  ์Šค๋ ˆ๋“œ๊ฐ€ ์ข…๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ๋Œ€๊ธฐ
        while (Thread.activeCount() > 1) {
            Thread.yield();
        }

        var end = System.currentTimeMillis();

        System.out.println("a_count: " + shared.a_count);
        System.out.println("b_count: " + shared.b_count);

        System.out.println("์‹คํ–‰ ์‹œ๊ฐ„: " + (end - start) + "ms");
    }
}

๋™์ž‘ ์ž์ฒด๋Š” ๊ธฐ๋Œ€ํ•œ ๋Œ€๋กœ ๋  ๊ฒƒ์ด๋‹ค.

๊ทผ๋ฐ ๋ฌธ์ œ๋Š” ์†๋„๋‹ค. synchronized๋Š” ๊ฐ์ฒด ์ „์ฒด๋ฅผ ์ž ๊ทธ๋Š” ๊ฑด๋ฐ, ์ € ์‚ฌ์šฉ ์‚ฌ๋ก€์—์„œ๋Š” ๊ตณ์ด ์ „์ฒด๋ฅผ ์ž ๊ธ€ ํ•„์š”๋Š” ์—†๋‹ค.
a๋Š” a๋Œ€๋กœ ์ž ๊ทธ๋ฉด ๋˜๊ณ , b๋Š” b๋Œ€๋กœ ์ž ๊ทธ๋ฉด ๋˜๋Š”๋ฐ, a์— ์ ‘๊ทผํ•˜๋Š”๋ฐ๋„ b๊นŒ์ง€ ์ž ๊ฐ€๋ฒ„๋ฆฌ๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

a์™€ b์— ๋Œ€ํ•ด ๋ณ„๋„์˜ Lock ์ฒ˜๋ฆฌ๋ฅผ ๋”ํ•˜๋ฉด ๋ถˆํ•„์š”ํ•œ Lock์œผ๋กœ ์ธํ•œ ์œ ์‹ค ์‹œ๊ฐ„์„ ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค.

๊ฐ๊ฐ์˜ Lock์„ ๋ช…์‹œ์ ์œผ๋กœ ์ถ”๊ฐ€ํ•˜๊ณ 


์ ‘๊ทผ ์ง€์ ์— lock์„ ๊ฑธ์–ด์ค€๋‹ค.

๊ทธ๋Ÿฌ๋ฉด

package org.example;

import java.util.concurrent.locks.ReentrantLock;

class SharedObject {
    public int a_count = 0;
    public int b_count = 0;

    public ReentrantLock a_lock = new ReentrantLock();
    public ReentrantLock b_lock = new ReentrantLock();

    public void increment_a() {
        a_lock.lock();
        a_count++;
        a_lock.unlock();
    }

    public void increment_b() {
        b_lock.lock();
        b_count++;
        b_lock.unlock();
    }
}

public class Main {
    public static void main(String[] args) {
         var shared = new SharedObject();

         var start = System.currentTimeMillis();

        // ์Šค๋ ˆ๋“œ๋ฅผ 5๊ฐœ ์ƒ์„ฑํ•ด์„œ count๋ฅผ ์ฆ๊ฐ€์‹œํ‚ด
        for (int i = 0; i < 5; i++) {
            Thread thread = new Thread(() -> {
                for (int j = 0; j < 10000000; j++) {
                    shared.increment_a();
                    shared.increment_b();
                }
            });
            thread.start();
        }

        // ๋ชจ๋“  ์Šค๋ ˆ๋“œ๊ฐ€ ์ข…๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ๋Œ€๊ธฐ
        while (Thread.activeCount() > 1) {
            Thread.yield();
        }

        var end = System.currentTimeMillis();

        System.out.println("a_count: " + shared.a_count);
        System.out.println("b_count: " + shared.b_count);

        System.out.println("์‹คํ–‰ ์‹œ๊ฐ„: " + (end - start) + "ms");
    }
}

์ „์—๋Š” 2์ดˆ์ฏค ๊ฑธ๋ฆฌ๋˜๊ฒŒ ์ด์ œ 1์ดˆ ๋ฏธ๋งŒ์œผ๋กœ ์ฒ˜๋ฆฌ๋˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.




ReenterantLock: ๊ณต์ •์„ฑ (fairness)

Lock ๊ฒฝํ•ฉ์ด ๋งค์šฐ ์‹ฌํ•œ ์ƒํ™ฉ์—์„œ๋Š”, ์šด์ด ์ข‹์ง€ ๋ชปํ•˜๋‹ค๋ฉด ํŠน์ • ์Šค๋ ˆ๋“œ๋งŒ ๊ณ„์†ํ•ด์„œ Lock์„ ์ ์œ ํ•˜์ง€ ๋ชปํ•  ์ˆ˜ ์žˆ๋‹ค.
์ด๋Ÿฐ ํ˜„์ƒ์„ ๋ถˆ๊ณต์ •(unfair)ํ•˜๋‹ค๊ณ  ํ•œ๋‹ค.

ReenterantLock์€ ๊ณต์ •ํ•œ Lock ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•œ๋‹ค.
์ƒ์„ฑ์ž์— true๋ฅผ ๋„˜๊ธฐ๋ฉด ๊ณต์ • ๋ชจ๋“œ๋กœ ์ž‘๋™ํ•ด์„œ, ์Šค๋ ˆ๋“œ๋“ค์ด ๊ณต์ •ํ•˜๊ฒŒ Lock์„ ์ ์œ ํ•˜๋„๋ก ์œ ๋„ํ•œ๋‹ค.
์˜ˆ๋ฅผ ๋“ค๋ฉด, ๊ฐ€์žฅ ์˜ค๋ž˜ ๊ธฐ๋‹ค๋ฆฐ ์Šค๋ ˆ๋“œ์—๊ฒŒ Lock ์šฐ์„ ์ˆœ์œ„๋ฅผ ์ฃผ๋Š” ๊ฒƒ์ด๋‹ค.

๋‹จ, ๊ณต์ •์„ฑ์ด ๋ฐ˜๋“œ์‹œ ๋ณด์žฅ๋˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค. ๊ฐ€์žฅ ์˜ค๋ž˜ ๊ธฐ๋‹ค๋ฆฐ ์Šค๋ ˆ๋“œ๋ฅผ ์„ ํ˜ธ(favor)ํ•˜๋Š” ๊ฒƒ์ผ ๋ฟ์ด๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๊ณต์ •์„ฑ์€ ๊ณต์งœ๋กœ ์ฃผ์–ด์ง€๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ, ์ถ”๊ฐ€์ ์ธ ๋™๊ธฐํ™”๋‚˜ ๋กœ์ง์ด ๋“ค์–ด๊ฐ€๋Š” ๊ฒƒ์ด๋‹ค.
๊ทธ๋ž˜์„œ ๊ธฐ๋ณธ ๋™์ž‘๋ณด๋‹ค ํ›จ์”ฌ ๋А๋ ค์งˆ ์ˆ˜ ์žˆ๋‹ค.




ReenterantLock: ์žฌ์ง„์ž… ๊ฐ€๋Šฅ

์‚ฌ์‹ค ์ด๊ฑธ ์ข‹์€ ๋””์ž์ธ์ด๋ผ ํ•  ์ˆ˜ ์žˆ๋Š”์ง€๋Š” ๋ชจ๋ฅด๊ฒ ๋Š”๋ฐ... synchronized์™€ ReenterantLock์€ ์žฌ์ง„์ž… ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•œ๋‹ค.
์ด๊ฒŒ ๋ฌด์Šจ ๋ง์ด๋‚˜๋ฉด, ์ด๋ฏธ Lock์„ ์žก์€ ์Šค๋ ˆ๋“œ๊ฐ€ Lock์„ ์ค‘๋ณตํ•ด์„œ ๋˜ ์žก์„ ์ˆ˜ ์žˆ๋‹ค๋Š” ๋ง์ด๋‹ค.

๊ทธ๋ž˜์„œ ์ด๋ž˜๋„ ์ž˜ ๋™์ž‘ํ•œ๋‹ค.

๊ทผ๋ฐ ์ด๋Ÿฐ ์ฝ”๋“œ๋ฅผ ์ข‹์€ ์ฝ”๋“œ๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ์„์ง€๋Š” ์ž˜ ๋ชจ๋ฅด๊ฒ ๋‹ค.




ReentrantLock: timeout ๊ธฐ๋ฐ˜ Lock

๊ธฐ์กด์˜ Lock ๊ธฐ๋Šฅ๋“ค์€ Lock์„ ์ ์œ ํ•  ๋•Œ๊นŒ์ง€ ํ•˜์—ผ์—†์ด ๊ธฐ๋‹ค๋ฆฐ๋‹ค.
๊ทผ๋ฐ ๊ฒฝ์šฐ์— ๋”ฐ๋ผ์„œ๋Š” ๋‹น์žฅ Lock์„ ์ ์œ ํ•  ์ˆ˜ ์—†๋‹ค๋ฉด ๋‹ค๋ฅธ ์ž‘์—…์„ ๋” ์ฒ˜๋ฆฌํ•˜๋„๋ก ๊ตฌํ˜„์„ ํ•˜๋Š”๊ฒŒ ์ฒ˜๋ฆฌ๋Ÿ‰ ์ธก๋ฉด์—์„œ ์œ ๋ฆฌํ•œ ์ƒํ™ฉ์ด ์žˆ์„ ์ˆ˜๋„ ์žˆ๋‹ค.

tryLock์„ ์‚ฌ์šฉํ•˜๋ฉด Lock์„ ์žก๋‹ค๊ฐ€ timeout์ด ์ง€๋‚˜๋ฉด ํฌ๊ธฐํ•˜๊ณ  ๋‚˜์˜ค๋„๋ก ํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  Lock์„ ์žก๋Š”๋ฐ ์„ฑ๊ณตํ•œ๋‹ค๋ฉด tryLock์€ true๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.




ReentrantReadWriteLock๋ฅผ ํ†ตํ•œ Lock

ReentrantReadWriteLock์€ ๋‹ค๋ฅธ ์–ธ์–ด์˜ Read-Write-Mutex์™€ ๋™๋“ฑํ•œ Lock ๊ตฌํ˜„์ฒด๋‹ค.

ReentrantLock์—๋Š” ์กฐ๊ธˆ ์„ฑ๋Šฅ์ ์ธ ๋‹จ์ ์ด ์žˆ๋‹ค.
์ฝ๊ธฐ ๋น„์ค‘์ด ๋งค์šฐ ๋†’์€ ๊ฒฝ์šฐ์—๋Š” Lock์œผ๋กœ ์ธํ•œ ์„ฑ๋Šฅ ์†์‹ค์ด ๊ฝค ์ปค์งˆ ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

๊ทธ๋Ÿฐ๋ฐ ์•Œ๋‹ค์‹œํ”ผ, read์— ๋Œ€ํ•œ ๋™๊ธฐํ™”๋Š” write์— ๋น„ํ•˜๋ฉด ๊ฝค ์ €๋ ดํ•˜๋‹ค. ์ฝ๊ธฐ๋ฅผ ํ•˜๋Š”๋ฐ write ์ˆ˜์ค€์˜ Lock์„ ํ•ญ์ƒ ๊ฑธ ํ•„์š”๋Š” ์—†๋Š” ๊ฒƒ์ด๋‹ค.

๊ทธ๋ž˜์„œ ReadWriteLock์€ read์™€ write์— ๋Œ€ํ•œ Lock์„ 2๋‹จ๊ณ„๋กœ ์ œ์–ดํ•˜๋Š” Lock์ด๋‹ค. ์ด๋ฅผ ํ†ตํ•ด read ๋ถ€ํ•˜๊ฐ€ ๋†’์€ ๊ฒฝ์šฐ์—๋Š” ์ผ๋ฐ˜ ReentrantLock๋ณด๋‹ค ๋‚˜์€ ์„ฑ๋Šฅ์„ ๊ธฐ๋Œ€ํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ธฐ๋ณธ์ ์ธ ์‚ฌ์šฉ ์›๋ฆฌ๋Š” ํฌ๊ฒŒ ๋‹ค๋ฅด์ง€ ์•Š๋‹ค.

๋Œ€์‹ 

writeLock๊ณผ


readLock์„ ๋ช…์‹œ์ ์œผ๋กœ ๊ฑธ ์ˆ˜ ์žˆ๋‹ค.

writeLock์„ ๊ฑธ๋ฉด ๋‹ค๋ฅธ writeLock๊ณผ readLock์ด ๋ชจ๋‘ ์ฐจ๋‹จ๋˜์ง€๋งŒ, readLock์€ ๋‹ค๋ฅธ Lock์„ ์ฐจ๋‹จํ•˜์ง€ ์•Š๋Š”๋‹ค.
์–ด์ฐจํ”ผ writeLock์„ ๋งŽ์ด ๊ฑด๋‹ค๋ฉด ReentrantLock๋งŒ ์“ฐ๋Š”๊ฒŒ ๋” ๋‹จ์ˆœํ•˜๊ณ  ์„ฑ๋Šฅ์ด ์ž˜ ๋‚˜์˜ฌ ์ˆ˜๋„ ์žˆ๋‹ค.




StampedLock๋ฅผ ํ†ตํ•œ Lock

StampedLock๋Š” ReentrantReadWriteLock์˜ ์กฐ๊ธˆ ๋” ๋‚™๊ด€์ ์ธ ๋ฒ„์ „์ด๋‹ค.
์Šค๋ ˆ๋“œ์˜ ์žฌ์ง„์ž…์„ ํ—ˆ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค.
๊ทธ๋ฆฌ๊ณ  write lock์ด ์žกํ˜€์žˆ๋Š” ์ƒํƒœ๋ผ๋„ read lock์„ ๋А์Šจํ•˜๊ฒŒ ์žก์„ ์ˆ˜ ์žˆ๋‹ค๋Š”๊ฒŒ ํŠน์ง•์ด๋‹ค.


์ดˆ๊ธฐํ™” ๋ฐฉ๋ฒ•์€ ํฌ๊ฒŒ ๋‹ค๋ฅผ๊ฒŒ ์—†๊ณ 


write Lock์„ ์žก๋Š” ๊ฒƒ๋„ ReentrantReadWriteLock์™€ ํฌ๊ฒŒ ๋‹ค๋ฅด์ง€ ์•Š๋‹ค.

๋‹ค๋ฅธ๊ฑด Read Lock์„ ์žก๋Š” ๋ถ€๋ถ„์ด๋‹ค.
Read Lock์„ ์žก์„๋•Œ๋Š” tryOptimisticRead์„ ์ฃผ๋กœ ์‚ฌ์šฉํ•˜๋Š”๋ฐ, ์ด๊ฑด write lock์ด ์žกํ˜€์žˆ๋“  ๋ง๋“  ์ผ๋‹จ ๊ฐ€์ ธ์˜จ๋‹ค.

๊ทผ๋ฐ ๋‹น์—ฐํžˆ write๊ฐ€ ๋ถˆ์™„์ „ํ•˜๊ฒŒ ์ฒ˜๋ฆฌ๋œ ์ƒํ™ฉ์—์„œ๋Š” ์• ๋งคํ•œ ๊ฐ’์ด๋‚˜ ์˜›๋‚  ๊ฐ’์„ ์ฐธ์กฐํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

์—ฌ๊ธฐ์„œ ํ•ต์‹ฌ์€ lock.validate๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์Šคํƒฌํ”„ ๊ฐ’ ๊ธฐ๋ฐ˜์œผ๋กœ ๊ฒ€์ฆ์„ ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด๋‹ค.
๊ฒ€์ฆ์— ์‹คํŒจํ•œ๋‹ค๋ฉด ๊ทธ์ œ์„œ์•ผ readLock์œผ๋กœ Lock์„ ๋Œ€๊ธฐํ•˜๊ณ  ์ตœ์‹  ๊ฐ’์„ ์ฒ˜๋ฆฌํ•˜๊ฒŒ ํ•˜๋ฉด ๋˜๊ณ , ๊ฒ€์ฆ์— ์„ฑ๊ณตํ•œ๋‹ค๋ฉด ๊ทธ๋Œ€๋กœ ์จ๋„ ๋œ๋‹ค.



์ฐธ์กฐ
https://velog.io/@may_yun/JAVA-synchronized-VS-Reentrant-Lock-%EC%B0%A8%EC%9D%B4%EC%A0%90
https://stackoverflow.com/questions/60903107/understanding-fair-reentrantlock-in-java
https://stackoverflow.com/questions/57809112/reentrantlock-vs-reentrantreadwritelock
https://stackoverflow.com/questions/26094200/what-is-stampedlock-in-java
https://stackoverflow.com/questions/55766479/how-to-to-use-stampedlock-optimistic-locking-i-cant-understand-code-sample-fr