在能同步的地方都已经同步了,为什么还是发生线程污染?

发布于 2022-09-11 18:33:45 字数 1781 浏览 16 评论 0

问题
这是一段Java学习中的例程,四个车站分别抢票。但是无法实现线程安全。

需求
实现线程安全

注释
saleT代表车站的类
静态类balance代表剩余的票数
s1-s4分别代表四个车站
我在能用sync修饰的地方都打上了sync,为什么还是无法实现线程安全?

↓下面是代码内容

package com.hssgweb.多线程;


//import java.util.concurrent.locks.ReentrantLock;

class  balance{
     static  double b = 1000;
        public static  double getB() {
            return b;
        }
        public  static   void setB(double b) {
            balance.b = b;
        }
    }
public class 铁路12306 {
    public  static void main(String[] args) {   //主方法

        SaleT s1 = new SaleT("1号");
        SaleT s2 = new SaleT("2号");
        SaleT s3 = new SaleT("3号");
        SaleT s4 = new SaleT("4号");
        
        Thread  th1 = new Thread(s1);
        Thread th2 = new Thread(s2);
        Thread th3 = new Thread(s3);
        Thread th4 = new Thread(s4);
        
        th1.start();
        th2.start();
        th3.start();
        th4.start();
    }
}
class SaleT implements Runnable {
//    Lock lock = new ReentrantLock();    
        String saleId;
        double balan;
    public   SaleT(String saleId ) {
        super();
        this.saleId = saleId;
    }
       synchronized void  pay(){          //pay方法

        balan = balance.getB()-1;    //剩余票数等于原来的票数减1
        balance.setB(balan);         
        /*System.out.println(balan);
        balan = ti.b.getB();*/    
        }

    int i = 0; //记录一下这玩意儿总共抢了多少张票
    
    public synchronized   void run() {

        while(balance.getB() > 0) {
            pay();
            System.out.println("我是" + saleId + "我为自己代言" + "---还剩下" + balance.getB());
            i++;
        }
        System.out.println("我是" + saleId + "我抢了" + i);
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

回忆躺在深渊里 2022-09-18 18:33:45

你同步啥了...synchronized方法锁的是实例对象 你4个对象 每个对象一把锁 自己和自己抢锁 谁都能进去 哪里同步了

旧人哭 2022-09-18 18:33:45

synchronized关键字的底层实现是对象锁,它是作用于某一个对象上的。对于一个以synchronized修饰的方法来说,如果它不是静态方法,那么加锁的对象就是本对象即this;如果它是静态方法,那么加锁的对象是这个类的Class对象(可以用getClass()获得)。
在你的代码中,s1、s2、s3和s4是四个不同的对象,因此有四把不同的锁分别控制这四个对象的run()方法,这四个线程同时操作同一个静态变量balance.b,四把锁之间是互不影响的,因此这个代码根本就没有体现任何的线程安全。
你应该使用同一把锁控制这四个线程对b的读写过程,或者将b修改为原子类型。

// 使用同一把锁,最简单的方式是将pay()改为静态方法
static synchronized double pay() {
    double d = Balance.getB();  // 类名应该大写
    if(d >= 1.0) {
        d -= 1.0;
        Balance.setB(d);
        return d;
    } else {
        return -1.0;
    }
}

public void run() {
    double b;
    while((b = pay()) >= 0) {
        System.out.println(saleId + "支付成功,余额" + b);
    }
    System.out.println("支付失败,余额不足");
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文