一篇文章带你搞定 Java 中同步概念

一个多线程的程序如果是通过 Runnable 接口实现的,则意味着类中的属性将被多个线程共享,那么这就会造成,如果多个线程要操作同一资源就有可能出现资源的同步问题。

一、问题的引出

class MyThread implements Runnable{
    private int ticket = 5;//一共5张票
    public void run(){
        for(int i=0;i<10;i++){
            if(ticket>0){//判断是否有剩余票
                try{
                    Thread.sleep(10);//加入延迟
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
                System.out.println("卖票:ticket = " + ticket--);
            }
        }
    }
}

public class Root{
    public static void main(String[] args) {
        MyThread mt = new MyThread();//定义线程对象
        Thread t1 = new Thread(mt);//定义 Thread 对象
        Thread t2 = new Thread(mt);//定义 Thread 对象
        Thread t3 = new Thread(mt);//定义 Thread 对象
        t1.start();//启动线程
        t2.start();//启动线程
        t3.start();//启动线程
    }
}

在这里插入图片描述
由于程序中加入了延迟操作,所以在运行的最后出现了负数。
对于票数的操作步骤如下:
(1)判断票数是否大于 0,大于 0 则表示还有票可以卖
(2)如果票数大于 0 ,则将票卖出
但是在上面程序中,在步骤 (1)和步骤(2)之间加入了延迟操作,那么一个线程就有可能在还没有对票数进行减操作之前,其他线程就已经将票数减少了,这就出现了票数为负的情况。

想要解决这样的问题,就必须使用同步,也就是多个操作在同一时间段内只能有一个线程进行,其他线程要等待此线程完成之后才可以继续执行
在这里插入图片描述

二、使用同步解决问题

解决资源共享的同步操作,可以使用同步代码块和同步方法两种方式完成

1. 同步代码块

我们已知所谓的代码块就是指用“{}”括起来的一段代码,根据其位置和声明的不同,可以分为普通代码块、构造块、静态块3种,如果在代码块加上 synchronized 关键字,则此代码块就称为同步代码块

synchronized(同步对象){
	需要同步的代码;
}

在使用同步代码块时必须指定一个需要同步的对象,但一般都将当前对象(this)设置成同步对象

class MyThread implements Runnable{
    private int ticket = 5;//一共5张票
    public void run(){
        for(int i=0;i<10;i++){
            synchronized (this){//设置需要同步的操作
                if(ticket>0){//判断是否有剩余票
                    try{
                        Thread.sleep(10);//加入延迟
                    }catch (InterruptedException e){
                        e.printStackTrace();
                    }
                    System.out.println("卖票:ticket = " + ticket--);
                }
            }
        }
    }
}

public class Root{
    public static void main(String[] args) {
        MyThread mt = new MyThread();//定义线程对象
        Thread t1 = new Thread(mt);//定义 Thread 对象
        Thread t2 = new Thread(mt);//定义 Thread 对象
        Thread t3 = new Thread(mt);//定义 Thread 对象
        t1.start();//启动线程
        t2.start();//启动线程
        t3.start();//启动线程
    }
}

在这里插入图片描述

2. 同步方法

除了可以将需要的代码设置成同步代码外,也可以使用 synchronized 关键字将一个方法声明成同步方法。

synchronized 方法返回值 方法名称(参数列表){
}
class MyThread implements Runnable{
    private int ticket = 5;
    public void run(){//覆写 run() 方法
        for(int i=0;i<100;i++){
            this.sale();
        }
    }
    public synchronized void sale(){//声明同步方法
        if(ticket>0){
            try{
                Thread.sleep(10);//加入延迟
            }catch (InterruptedException e){
                e.printStackTrace();
            }
            System.out.println("卖票:ticket = " + ticket--);
        }
    }
}

public class Test{
    public static void main(String[] args) {
        MyThread mt = new MyThread();
        Thread t1 = new Thread(mt);//定义 Thread 对象
        Thread t2 = new Thread(mt);//定义 Thread 对象
        Thread t3 = new Thread(mt);//定义 Thread 对象
        t1.start();//启动线程
        t2.start();//启动线程
        t3.start();//启动线程
    }
}

在这里插入图片描述

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

南淮北安

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

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

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

打赏作者

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

抵扣说明:

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

余额充值