关键词搜索

源码搜索 ×
×

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

发布2020-01-17浏览479次

详情内容

一个多线程的程序如果是通过 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(同步对象){
    	需要同步的代码;
    }
    
    • 1
    • 2
    • 3

    在使用同步代码块时必须指定一个需要同步的对象,但一般都将当前对象(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();//启动线程
        }
    }
    
      28
    • 29

    在这里插入图片描述

    2. 同步方法

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

    synchronized 方法返回值 方法名称(参数列表){
    }
    
    • 1
    • 2
    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();//启动线程
        }
    }
    
      28
    • 29
    • 30

    在这里插入图片描述

    相关技术文章

    点击QQ咨询
    开通会员
    返回顶部
    ×
    微信扫码支付
    微信扫码支付
    确定支付下载
    请使用微信描二维码支付
    ×

    提示信息

    ×

    选择支付方式

    • 微信支付
    • 支付宝付款
    确定支付下载