学科分类
目录
Java基础

同步代码块

通过前面小节的学习,了解到线程安全问题其实就是由多个线程同时处理共享资源所导致的。要想解决线程安全问题,必须得保证处理共享资源的代码在任意时刻只能有一个线程访问。为此,Java中提供了线程同步机制。当多个线程使用同一个共享资源时,可以将处理共享资源的代码放置在一个使用synchronized关键字来修饰的代码块中,这段代码块被称作同步代码块,其语法格式如下:

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

上述代码中,lock是一个锁对象,它是同步代码块的关键。当线程执行同步代码块时,首先会检查锁对象的标志位,默认情况下标志位为1,此时线程会执行同步代码块,同时将锁对象的标志位置为0。当一个新的线程执行到这段同步代码块时,由于锁对象的标志位为0,新线程会发生阻塞,等待当前线程执行完同步代码块后,锁对象的标志位被置为1,新线程才能进入同步代码块执行其中的代码,这样循环往复,直到共享资源被处理完为止。这个过程就好比一个公用电话亭,只有前一个人打完电话出来后,后面的人才可以打。

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

文件1 Example12.java

 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所示。

图1 运行结果

文件1中,将有关tickets变量的操作全部都放到同步代码块中synchronized (lock) {},从图10-16可以看出,售出的票不再出现0和负数的情况,这是因为售票的代码实现了同步,之前出现的线程安全问题得以解决。

注意

同步代码块中的锁对象可以是任意类型的对象,但多个线程共享的锁对象必须是相同的。“任意”说的是共享锁对象的类型。所以,锁对象的创建代码不能放到run()方法中,否则每个线程运行到run()方法都会创建一个新对象,这样每个线程都会有一个不同的锁,每个锁都有自己的标志位,线程之间便不能产生同步的效果。

点击此处
隐藏目录