水晶心泉
2021-10-26 19:20
采纳率: 100%
浏览 34
已结题

多线程中对共享的Integer对象加锁,但仍出现安全问题

今天学了多线程,说在下面这个案例中如果不加锁的话,容易出现线程安全问题。所以我尝试了把多线程共享的tickeNumbers 加了锁,目的是每个线程执行到此处代码时会先看tr对象的这个tickeNumbers 变量有没有锁,如果没有就进入同步代码块中执行操作,否则就等待,这样就解决了同一张票卖多次的问题,但实际多执行几次后发现,还是会出现这种现象(),有能帮忙分析下原因的嘛

public class Demo01 {

    public static void main(String[] args) {
        TicketRunnable tr = new TicketRunnable();
        for (int i = 0; i < 4; i++) {
            Thread t = new Thread(tr,"窗口"+(i+1));
            t.start();
        }
    }
    
}
class TicketRunnable implements Runnable{
    Integer tickeNumbers = 100;
    @Override
    public void run() {
        String name = Thread.currentThread().getName();
        while(true){
            synchronized(tickeNumbers){
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (tickeNumbers <= 0) {
                    System.out.println("票卖光了");
                    break;
                }
                System.out.println(name + "售出:(" + (tickeNumbers--) + ")");

            }
        }
    }
}

实际执行结果(出现问题的一次):


窗口1售出:(100)
窗口1售出:(99)  //此处99号票被卖了两次
窗口4售出:(99)
窗口3售出:(97)
窗口1售出:(98)
窗口2售出:(96)
窗口3售出:(94)
窗口4售出:(95)
窗口3售出:(93)
窗口1售出:(92)
窗口2售出:(91)
窗口2售出:(90)
窗口4售出:(89)
窗口1售出:(87)
窗口3售出:(88)
窗口4售出:(86)
窗口2售出:(86)
窗口4售出:(85)
窗口3售出:(84)
窗口2售出:(83)
窗口4售出:(82)
窗口1售出:(83)
窗口2售出:(81)
窗口4售出:(80)
窗口3售出:(81)
窗口2售出:(79)
窗口1售出:(79)
窗口2售出:(78)
窗口3售出:(78)
窗口4售出:(77)
窗口1售出:(76)
窗口2售出:(75)
窗口1售出:(74)
窗口3售出:(72)
窗口2售出:(73)
窗口4售出:(74)
窗口1售出:(71)
窗口4售出:(70)
窗口1售出:(69)
窗口4售出:(68)
窗口1售出:(67)
窗口2售出:(67)
窗口4售出:(66)
窗口3售出:(65)
窗口1售出:(65)
窗口4售出:(64)
窗口2售出:(63)
窗口3售出:(62)
窗口4售出:(61)
窗口1售出:(60)
窗口2售出:(60)
窗口3售出:(60)
窗口4售出:(59)
窗口1售出:(58)
窗口4售出:(57)
窗口2售出:(56)
窗口1售出:(55)
窗口4售出:(54)
窗口1售出:(53)
窗口2售出:(52)
窗口3售出:(51)
窗口4售出:(50)
窗口1售出:(49)
窗口2售出:(48)
窗口3售出:(47)
窗口4售出:(46)
窗口1售出:(45)
窗口3售出:(44)
窗口4售出:(43)
窗口2售出:(42)
窗口1售出:(42)
窗口3售出:(41)
窗口4售出:(40)
窗口2售出:(39)
窗口3售出:(38)
窗口4售出:(37)
窗口2售出:(36)
窗口1售出:(36)
窗口3售出:(35)
窗口4售出:(34)
窗口2售出:(33)
窗口3售出:(32)
窗口4售出:(31)
窗口2售出:(30)
窗口1售出:(30)
窗口3售出:(29)
窗口4售出:(28)
窗口2售出:(27)
窗口3售出:(26)
窗口4售出:(25)
窗口2售出:(24)
窗口1售出:(24)
窗口3售出:(23)
窗口4售出:(22)
窗口2售出:(21)
窗口3售出:(20)
窗口4售出:(19)
窗口1售出:(18)
窗口2售出:(18)
窗口3售出:(17)
窗口4售出:(16)
窗口1售出:(15)
窗口3售出:(14)
窗口4售出:(13)
窗口1售出:(12)
窗口2售出:(11)
窗口3售出:(10)
窗口4售出:(9)
窗口1售出:(8)
窗口3售出:(7)
窗口4售出:(6)
窗口2售出:(5)
窗口1售出:(5)
窗口3售出:(4)
窗口4售出:(3)
窗口2售出:(2)
窗口3售出:(1)
票卖光了
票卖光了
票卖光了
票卖光了

Process finished with exit code 0
  • 写回答
  • 好问题 提建议
  • 追加酬金
  • 关注问题
  • 邀请回答

2条回答 默认 最新

  • CSDN专家-sinJack 2021-10-26 19:39
    最佳回答

    synchronized(Integer)时,当值发生改变时,基本上每次锁住的都是不同的对象实例。
    一般不使用线程消耗的对象作为锁对象。可以创建一个非消耗的对象。

    Integer lock=10;
    synchronized(lock)
    

    或者直接用当前对象作为锁对象。

    synchronized(this)
    
    评论
    解决 无用
    打赏 举报
查看更多回答(1条)