当前位置: java基础教程 > 11-java多线程 > 阅读正文

synchronized 关键字

2021.2.10.   511 次   1265字

当多线程访问共享数据时,就可能会出现线程安全问题

使用 synchronized 是解决线程安全的其中一种方式

1.synchronized 同步代码块语法
synchronized(锁对象){
    可能出现线程安全问题的代码(即访问了共享数据的代码);
}

注意事项:

  • 同步代码块的 “锁对象” 可以是任意类型的对象
  • 必须保证多个线程使用的是同一个锁对象
  • 锁对象的作用:只让一个线程在同步代码块中执行
2. synchronized 方法

作用和代码块差不多,写法是成员方法的语法, 在返回值修饰符前加 synchronized

可以理解为,它是一个用 this 作为锁对象的同步代码块,方便重复调用

访问修饰符 synchronized 返回值修饰符 方法名(参数列表){
    //方法体;
}
3. synchronized 静态方法

作用和代码块差不多,写法是静态方法的语法, 在返回值修饰符前加 synchronized

可以理解为, 它是使用 本类的class属性, 即class文件对象作为锁对象的同步代码块

访问修饰符 static synchronized 返回值修饰符 方法名(参数列表){
    //方法体;
}
4.例子(仅使用同步代码块示例,因为后两者实质相同,只是语法稍有差异)

创建一个 RunnableImpl 类,共有100张票,不断售卖直到票数等于0

创建一个 main 方法,让 3 个线程同时卖票,此时也是线程安全的

如果去掉 synchronized 代码块,那么就会出现卖不存在的票,重复卖票的情况

public class RunnableImpl implements Runnable{
    //定义一个多个线程共享的票源
    private  int ticket = 100;
    
    //创建一个锁对象
    Object obj = new Object();

    //设置线程任务:卖票
    @Override
    public void run() {
        //使用死循环,让卖票操作重复执行
        while(true){
        	synchronized(obj) {
                //先判断票是否存在
                if(ticket>0){
                    //提高安全问题出现的概率,让程序睡眠
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    //票存在,卖票 ticket--
                    System.out.println(Thread.currentThread().getName()+"-->正在卖第"+ticket+"张票");
                    ticket--;
                }
        	}
        }
    }
    public static void main(String[] args) {
        //创建Runnable接口的实现类对象
        RunnableImpl run = new RunnableImpl();
        //创建Thread类对象,构造方法中传递Runnable接口的实现类对象
        Thread t0 = new Thread(run);
        Thread t1 = new Thread(run);
        Thread t2 = new Thread(run);
        //调用start方法开启多线程
        t0.start();
        t1.start();
        t2.start();
    }
}

本篇完,还有疑问?

加入QQ交流群:11500065636 IT 技术交流群