synchronized关键词保证线程安全

在同一个JVM下,如何确保线程的安全呢?
本篇文章主要通过synchronized关键词确保线程的安全性,在不考虑线程池的情况下,线程的创建请参考上一篇文章。
通过一个通俗的案例,来更加形象的说明我们的线程是安全的,需求如下:我们现在总共有10张通往大理的飞机票,并且有三个售票窗口进行售票,该如何设计购票程序,使其不会有少售,多售的情况出现?
在不使用线程安全的情况下:

定义三个售票窗口如下:

MyRunableUnSyn myRunable = new MyRunableUnSyn();
Thread thread = new Thread(myRunable, "窗口一");
Thread thread1 = new Thread(myRunable, "窗口二");
Thread thread2 = new Thread(myRunable, "窗口三");
thread.start();
thread1.start();
thread2.start();

定义具体售票操作如下:

public class MyRunableUnSyn implements  Runnable {
    static int tickets = 10; // 定义十张票
    @Override
    public void run() {
        while (true){
                if (tickets > 0){
                    try {
                        Thread.sleep(1000);
                        System.out.println(Thread.currentThread().getName() +" 出售了第 " + tickets-- + " 张票");
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                }
        }
    }
}

此时进行卖票,肯定会出现同一张票多卖的情况,执行结果如下:
在这里插入图片描述

第一种:在使用线程安全的情况下

定义三个售票窗口如下:
说明 :
此时是不同线程是使用的同一个具体售票的对象,此时买票是串行操作

 MyRunable myRunable = new MyRunable();
 Thread thread = new Thread(myRunable, "窗口一");
 Thread thread1 = new Thread(myRunable, "窗口二");
 Thread thread2 = new Thread(myRunable, "窗口三");
 thread.start();
 thread1.start();
 thread2.start();

定义具体售票操作如下:

public class MyRunable implements  Runnable {
    static int tickets = 10; // 定义十张票
    @Override
    public void run() {
        while (true){
            synchronized (this){
                if (tickets > 0){
                    try {
                        Thread.sleep(1000);
                        System.out.println(Thread.currentThread().getName() +" 出售了第 " + tickets-- + " 张票");
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}

此时进行卖票,肯定不会出现多卖、少卖的情况,执行结果如下:
在这里插入图片描述

第二种:在使用线程安全的情况下

定义三个售票窗口如下:
此时这种情况下是并行操作的,线程不安全的,在线程中的变量不是共享的。

MyRunable myRunable1 = new MyRunable();
MyRunable myRunable2 = new MyRunable();
MyRunable myRunable3 = new MyRunable();
Thread thread3 = new Thread(myRunable1, "窗口一");
Thread thread4 = new Thread(myRunable2, "窗口二");
Thread thread5 = new Thread(myRunable3, "窗口二");
thread3.start();
thread4.start();
thread5.start();

将并行转成串行,线程是安全的,具体操作如下:

MyRunable myRunable1 = new MyRunable();
MyRunable myRunable2 = new MyRunable();
MyRunable myRunable3 = new MyRunable();
Thread thread3 = new Thread(myRunable1, "窗口一");
Thread thread4 = new Thread(myRunable2, "窗口二");
Thread thread5 = new Thread(myRunable3, "窗口二");
thread3.start();
thread4.start();
thread5.start();
// join()是将并行转为串行操作
thread3.join();
thread4.join();
thread5.join();

定义具体售票操作如下:
参考第一种

第三种:在使用线程安全的情况下,并行情况下保证线程安全

定义三个售票窗口如下:
并发情况

MyRunable myRunable1 = new MyRunable();
MyRunable myRunable2 = new MyRunable();
MyRunable myRunable3 = new MyRunable();
Thread thread3 = new Thread(myRunable1, "窗口一");
Thread thread4 = new Thread(myRunable2, "窗口二");
Thread thread5 = new Thread(myRunable3, "窗口二");
thread3.start();
thread4.start();
thread5.start();

定义具体售票操作如下:

public class MyRunable implements  Runnable {
    static int tickets = 10; // 定义十张票
    @Override
    public void run() {
        while (true){
            synchronized (MyRunable.class){
                if (tickets > 0){
                    try {
                        Thread.sleep(1000);
                        System.out.println(Thread.currentThread().getName() +" 出售了第 " + tickets-- + " 张票");
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}

为什么此种情况下,线程是安全的?
synchronized关键词锁的是当前同一个当前类,确保同步的是一个东西,所以线程是安全的

第四种:在使用线程安全的情况下,并行情况下保证线程安全(第三种的另一种写法)

定义三个售票窗口如下:
参考第三种

定义具体售票操作如下:

public class MyRunable implements  Runnable {

    static int tickets = 10; // 定义十张票

    @Override
    public void run() {
        while (true){
                if (tickets > 0){
                    try {
                        Thread.sleep(1000);
                        System.out.println(Thread.currentThread().getName() +" 出售了第 " + tickets-- + " 张票");
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                }
            }
    }
}

为什么此种情况下,线程是安全的?
因为每次静态方法每次调用的内部变量,都是局部变量,每次调用静态方法时都会为它重新分配内存空间,所以是安全的。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

胤墨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值