java线程冲突问题——不安全的线程例子

Java线程安全问题

在平时编程中,我们会经常用到多线程,尤其是android中,但多线程也特别容易带来问题,比如线程冲突、死锁等问题,为了加深理解,我们先来回顾一下线程冲突问题。

线程冲突

public class UserStat {
        int userCount;
        public int getUserCount() {
            return userCount;
        }
        public void increment() {
            userCount++;
        }
        public void decrement() {
            userCount--;
        }
}

假设当一个线程正在递增userCount变量时,另一个线程则试图通过调用getUserCount来读取该变量的值,这时会发生什么情况呢?请记住,userCount++语句实际上是由3个连续的步骤组成的:

  • 读取userCount的值,并将它保存在某个临时储存装置中
  • 递增这个值
  • 降递增的值写回到userCount

假设有一个线程负责读取和递增userCount的值。在它有机会存储递增的值之前,另一个线程会读取它,并且得到的是旧值。当第二个线程最终得到机会写入userCount时,它会替换掉第一个线程的递增值。两个非原子的操作在不同的线程中运行,却操作同一个数据,其中的交叉就称作线程冲突。

不安全的线程例子

下面我们从一个不安全的例子开始,分析一下线程冲突。

public class UnSafeThreadDemo {

    public UnSafeThreadDemo() {

    }
    /**
     * @author xuyan
     */
    public static void main(String[] args) throws InterruptedException {
        final UserStat us = new UnSafeThreadDemo().new UserStat();
        Thread th1 = new Thread("th1") {
            @Override
            public void run() {
                System.out.println(us.getUserCount() + " " + super.getName());
            }
        };
        Thread th2 = new Thread("th2") {
            @Override
            public void run() {
                System.out.println(us.getUserCount() + " " + super.getName());
            }
        };
        th1.start();
        // Thread.sleep(100);
        th2.start();
    }

    class UserStat {
        int userCount;
        public int getUserCount() {
            return userCount++;
        }
    }
}
  • 如果不执行Thread.sleep(1000);
  • 偶尔结果为:
  • 0 th2
  • 0 th1
  • 如果执行Thread.sleep(1000);
  • 结果为:
  • 0 th1
  • 1 th2

对于这样的多线程冲突问题,我们采用一种常规的解决方法,就是同步机制。让我们对操作加synchronized关键字:

class UserStat {
    int userCount;

    public synchronized int getUserCount() {
    return userCount++;
    }
}

注:synchronized 方法控制对类成员变量的访问: 每个类实例对应一把锁,每个 synchronized 方法都必须获得调用该方法的类实例的锁方能执行,否则所属 线程阻塞 ,方法一旦执行,就独占该锁,直到从该方法返回时才将锁释放,此后被阻塞的线程方能获得该锁,重新进入可 执行状态。这种机制确保了同一时刻对于每一个类实例,其所有声明为 synchronized 的成员函数中至多只有一个处于可执行状态(因为至多只有一个能够获得该类实例对应的锁),从而有效避免了类成员变量的访问冲突(只要所有可能访问类成员变量的方法均被声明为 synchronized)。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值