synchronized

กรณีที่หลายเธรด (thread) เข้าไปแก้ไขตัวแปรตัวเดียวกัน อาจจะเกิดปัญหา lost update ได้

เธรด worker1, worker2 (บรรทัดที่ 20, 21) เข้าไปแก้ไขตัวแปร n (บรรทัดที่ 3) ตัวเดียวกัน

public class Race {
    class Job implements Runnable {
        private int n = 0;

        public void go() {
            int one = 1;
            for (int i = 0; i < 100000000; i++) {
                n += one;
            }
        }

        public void run() {
            go();
            System.out.println(n);
        }
    }

    public void begin() {
        Job job = new Job();
        Thread worker1 = new Thread(job);
        Thread worker2 = new Thread(job);
        worker1.start();
        worker2.start();
    }

    public static void main(String[] args) {
        new Race().begin();
    }
}

ลูปในเมธอด go() สั่งเพิ่มค่า n ร้อยล้านครั้ง เนื่องจากมีสองเธรด ค่า n จึงต้องเพิ่มเป็นสองร้อยล้าน

แต่การรันครั้งแรกที่เครื่องผมได้ผลดังนี้

147432898
170592452

รันครั้งที่สองที่เครื่องผมได้ผลดังนี้

176458597
184258902

รันครั้งต่อไปก็น่าจะได้ผลที่แตกต่างกันออกไป แต่ค่า n ที่พิมพ์ออกมาไม่เท่ากับสองร้อยล้าน เพราะการเปลี่ยนค่า n บางครั้งไม่เสร็จสมบูรณ์

ปัญหานี้สามารถแก้ไขโดยใช้คีย์เวิร์ด synchronized

synchronized เมื่อนำมาขยายที่เมธอด หมายถึงถ้ามีหลายๆเธรด (thread) เข้ามาเรียกเมธอดนี้ของวัตถุชิ้นเดียวกัน จะมีเพียงเธรดเดียวเท่านั้นที่สามารถรันโค้ดในเมธอดนี้ได้

เพิ่มคำ่ว่า synchronized ที่บรรทัดที่ 5

public class Race {
    class Job implements Runnable {
        private int n = 0;

        synchronized public void go() {
            int one = 1;
            for (int i = 0; i < 100000000; i++) {
                n += one;
            }
        }

        public void run() {
            go();
            System.out.println(n);
        }
    }

    public void begin() {
        Job job = new Job();
        Thread worker1 = new Thread(job);
        Thread worker2 = new Thread(job);
        worker1.start();
        worker2.start();
    }

    public static void main(String[] args) {
        new Race().begin();
    }
}

ผลการทำงานคือ

1000000000
2000000000

ถึงแม้ synchronized จะช่วยแก้ปัญหา lost update ได้ แต่ก็อาจจะทำให้เกิดปัญหา deadlock

public class Deadlock {
    static class A {
        A next;

        synchronized void go() {
            try {
                Thread.sleep(1000);
                next.go();
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }
    
    static class Job implements Runnable {
        A a;

        public void run() {
            a.go();
            System.out.println("end");
        }
    }

    public static void main(String[] args) {
        A a1 = new A();
        A a2 = new A();
        a1.next = a2;
        a2.next = a1;

        Job job1 = new Job();
        Job job2 = new Job();
        job1.a = a1;
        job2.a = a2;

        Thread t1 = new Thread(job1);
        Thread t2 = new Thread(job2);
        t1.start();
        t2.start();
    }
}

หนังสือ เขียนโปรแกรม Java เบื้องต้น

หนังสือ Java Keywords

หากจะนำข้อความไปใช้ ต้องแสดงที่มา และห้ามใช้ในเชิงพาณิชย์

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s