位置:首页 > Java > 同步代码块

同步代码块

时间:2026-08-15  |  作者:火苗实验室  |  阅读:0

线程安全问题的根源

结合前面几个小节的内容,其实不难看出:线程安全问题的根源,就出在多个线程同时操作同一份共享资源上。

要把这个问题处理好,关键就在于保证操作共享资源的那段代码,在任何时刻都只能由一个线程进入。

也正因为如此,Ja va专门提供了线程同步机制。多个线程一旦需要共同使用同一个共享资源,就可以把相关操作放进一个由synchronized关键字修饰的代码块里。

这样的代码块,通常就叫作同步代码块,它的语法格式如下:

synchronized(lock){
// 操作共享资源代码块
...
}

同步代码块的执行过程

在这段代码里,lock就是那个起决定作用的锁对象,也是整个同步代码块能够有序执行的关键。

线程一旦运行到同步代码块,先要看一眼这个锁对象的标志位。默认情况下,标志位是1,这意味着锁当前可用,线程就可以进入同步代码块执行,同时把锁对象的标志位改成0。

接下来,如果有新的线程也走到这里,因为看到标志位已经是0,就没法继续往下执行,只能先阻塞等待。

要等到当前线程把同步代码块执行完,锁对象的标志位重新变回1,后面的线程才有机会进入并执行其中的代码。

整个过程就是这样反复进行,直到共享资源全部处理完成。

说得直白一点,这就像一个公用电话亭,前一个人没打完电话出来,后面的人就只能排队等着。

售票代码的同步改造

接下来将售票的代码放到synchronized区域中进行修改,如文件1所示。

文件1 Example12.ja va

 1    // 定义SaleThread2类实现Runnable接口
 2        class SaleThread2 implements Runnable {
 3            private int tickets = 10;    // 10张票
 4            Object lock = new Object();  // 定义任意一个对象,用作同步代码块的锁
 5            public void run() {
 6                while (true) {
 7                    synchronized (lock) { // 定义同步代码块
 8                        if (tickets > 0) {
 9                            try {
 10                                Thread.sleep(100); // 模拟售票耗时过程
 11                            } catch (InterruptedException e) {
 12                                e.printStackTrace();
 13                            }
 14                            System.out.println(Thread.currentThread().getName() 
 15                                    + " 正在发售第 " + tickets-- + " 张票 ");
 16                        }
 17                    }
 18                }
 19            }
 20        }
 21        public class Example12 {
 22            public static void main(String[] args) {
 23                SaleThread2 saleThread = new SaleThread2();
 24                // 创建并开启四个线程,模拟4个售票窗口
 25                new Thread(saleThread, "窗口1").start();
 26                new Thread(saleThread, "窗口2").start();
 27                new Thread(saleThread, "窗口3").start();
 28                new Thread(saleThread, "窗口4").start();
 29            }
 30        }

运行结果如图1所示。

同步代码块_wishdown.com

图1 运行结果

运行结果分析

文件1中,将有关tickets变量的操作全部都放到同步代码块中synchronized (lock) {}。

从图10-16可以看出,售出的票不再出现0和负数的情况,这是因为售票的代码实现了同步,之前出现的线程安全问题得以解决。

注意

同步代码块中的锁对象可以是任意类型的对象,但多个线程共享的锁对象必须是相同的。

“任意”说的是共享锁对象的类型。所以,锁对象的创建代码不能放到run()方法中,否则每个线程运行到run()方法都会创建一个新对象。

这样每个线程都会有一个不同的锁,每个锁都有自己的标志位,线程之间便不能产生同步的效果。

免责声明:文中图文均来自网络,如有侵权请联系删除,心愿游戏发布此文仅为传递信息,不代表心愿游戏认同其观点或证实其描述。

相关文章

更多

精选合集

更多

大家都在玩

热门话题

大家都在看

更多