千锋教育-做有情怀、有良心、有品质的职业教育机构

400-811-9990
手机站
千锋教育

千锋学习站 | 随时随地免费学

千锋教育

扫一扫进入千锋手机站

领取全套视频
千锋教育

关注千锋学习站小程序
随时随地免费学习课程

上海
  • 北京
  • 郑州
  • 武汉
  • 成都
  • 西安
  • 沈阳
  • 广州
  • 南京
  • 深圳
  • 大连
  • 青岛
  • 杭州
  • 重庆
当前位置:重庆千锋IT培训  >  技术干货  >  synchronized中使用Integer带来的问题

synchronized中使用Integer带来的问题

来源:千锋教育
发布人:lxl
时间: 2023-05-19 10:15:17

synchronized中使用Integer带来的问题

  今天,给学生讲了多线程中线程安全的问题。

  刚下课,就有学生过来问:"不是说在加锁时,使用同一个对象作为锁就能解决线程安全问题么?但是我的代码怎么不行呢?"

  我看了下他的代码,如下:

  public class TestMain {

  public static void main(String[] args) {

  Seller s1 = new Seller("张三");

  Seller s2 = new Seller("李四");

  Seller s3 = new Seller("王五");

  s1.start();

  s2.start();

  s3.start();

  }

  }

  class Seller extends Thread{

  private String name;

  public static Integer ticket = 10;

  public Seller(String name) {

  this.name = name;

  }

    @Override
public void run() {
while(ticket > 0) {
System.out.println(name + "开始卖票");
synchronized (ticket) {
if(ticket > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
ticket--;
System.out.println(name + "卖出了一张票,还剩"+ticket+"张票");
}
}
}
}

   我发现其synchronized方法中的对象是ticket,这是一个有意思的问题。

  因为ticket是Integer类型的,在加锁的时候确实是类属性,在多个对象中共享一个,所以说是锁的一个对象也没有问题,但是在下面的代码中又对ticket进行了改变,那么就不是同一个对象了。

  打开Integer的源代码可以看到如下代码:

  public static Integer valueOf(int i) {

  // 当传入的值范围是-128~127之间时,直接返回

  if (i >= IntegerCache.low && i <= IntegerCache.high)

  return IntegerCache.cache[i + (-IntegerCache.low)]; // 相应的下标

  return new Integer(i); // 不在此范围则创建一个新对象

  }

  private static class IntegerCache {

  static final int low = -128; // 最小值

  static final int high; // 最大值

  static final Integer cache[]; // 整型数组

 

// 静态代码块,在类加载时执行
static {
// high value may be configured by property
int h = 127; // 最大值
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h; // 如果没有配置,最大值127

cache = new Integer[(high - low) + 1]; // 数组大小256
int j = low;
for(int k = 0; k < cache.length; k++) // 循环范围0~255
cache[k] = new Integer(j++);

// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}

private IntegerCache() {}

   上面的代码意味着Integer在自动装箱和拆箱时,并非是直接对值进行修改,而是返回常量池数组中另一个对象或者创建一个新对象。导致上面的synchronized中的加锁对象,在加锁后进行修改后,变成了另一个对象,那么锁失效是很自然的问题。

  那么可以修改如下,可以解决该问题:

  public class TestMain {

  public static void main(String[] args) {

  Seller s1 = new Seller("张三");

  Seller s2 = new Seller("李四");

  Seller s3 = new Seller("王五");

  s1.start();

  s2.start();

  s3.start();

  }

  }

  class Seller extends Thread{

  private String name;

  public static Integer ticket = 10;

  public Seller(String name) {

  this.name = name;

  }

 

@Override
public void run() {
while(ticket > 0) {
System.out.println(name + "开始卖票");
synchronized (A.obj) {
if(ticket > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
ticket--;
System.out.println(name + "卖出了一张票,还剩"+ticket+"张票");
}
}
}
}
}

class A{
public static final Object obj = new Object();
}

 

声明:本站稿件版权均属千锋教育所有,未经许可不得擅自转载。

猜你喜欢LIKE

如何进行mysql数据备份?

2023-05-30

从零开始学Java之Java中的内部类是怎么回事?

2023-05-29

什么是事件流以及事件流的传播机制 ?

2023-05-29

最新文章NEW

什么是servlet的生命周期?servlet请求处理流程是怎样的?

2023-05-30

在java中,super关键字怎样使用

2023-05-29

什么是JavaScript伪数组?

2023-05-25

相关推荐HOT

更多>>

快速通道 更多>>

最新开班信息 更多>>

网友热搜 更多>>