Java非线程安全问题的解决方法

在上节《多线程之间访问实例变量》中出现了一个术语——非线程安全。非线程安全主要是指多个线程对同一个对象中的同一个实例变量进行操作时会出现值被更改、值不同步的情况,进而影响程序的执行流程。下面用一个示例来学习一下如何解决非线程安全问题。

本案例模拟了多线程下的用户登录验证功能。首先编写一个类实现验证功能, LoginCheck 类的代码如下:

 
  1. package ch14;
  2. public class LoginCheck
  3. {
  4. private static String username;
  5. private static String password;
  6. public static void doPost(String _username,String _password)
  7. {
  8. try
  9. {
  10. username=_username;
  11. if (username.equals("admin"))
  12. {
  13. Thread.sleep(5000);
  14. }
  15. password=_password;
  16. System.out.println("username="+username+"password="+password);
  17. }
  18. catch(InterruptedException e)
  19. {
  20. // TODO Auto-generated catch block
  21. e.printStackTrace();
  22. }
  23. }

}

接下来创建线程类 LoginThreadA 和 LoginThreadB,这两个线程都调用 LoginCheck 类进行登录信息。其中 LoginThreadA 类的代码如下:

 
  1. package ch14;
  2. public class LoginThreadA extends Thread
  3. {
  4. public void run()
  5. {
  6. LoginCheck.doPost("admin","admin");
  7. }
  8. }


LoginThreadB 类的代码如下:

 
  1. package ch14;
  2. public class LoginThreadB extends Thread
  3. {
  4. public void run()
  5. {
  6. LoginCheck.doPost("root","root");
  7. }
  8. }


现在编写主线程程序,分别创建 LoginThreadA 线程实例和 LoginThreadB 线程实现,然后启动这两个线程。主线程的代码如下:

 
  1. package ch14;
  2. public class Test07
  3. {
  4. public static void main(String[] args)
  5. {
  6. LoginThreadA a=new LoginThreadA();
  7. a.run(); //启动线程LoginThreadA
  8. LoginThreadB b=new LoginThreadB();
  9. b.run(); //启动线程LoginThreadB
  10. }
  11. }


程序运行后的结果如下所示:

username=root password=admin
username=root password=root


从运行结果中可以看到用户名 root 出现了这两次,这是由于多个线程同时修改 username,导致值不一致的情况。

仔细查看代码可以发现问题出现在两个线程都会调用 doPost() 方法上。解决这个非线程安全问题的方法是使用 synchronized 关键字修饰 doPost() 方法,即不允许多个线程同时修改 doPost() 方法中的变量。更改代码如下:

 
  1. package ch14;
  2. public class LoginCheck
  3. {
  4. private static String username;
  5. private static String password;
  6. synchronized public static void doPost(String _username,String _password)
  7. {
  8. try
  9. {
  10. username=_username;
  11. if (username.equals("admin"))
  12. {
  13. Thread.sleep(5000);
  14. }
  15. password=_password;
  16. System.out.println("username="+username+"password="+password);
  17. }
  18. catch (InterruptedException e)
  19. {
  20. // TODO Auto-generated catch block
  21. e.printStackTrace();
  22. }
  23. }
  24. }


再次运行主线程,此时将看到如下所示的结果,说明不存在“非线程安全”问题了。

username=admin password=admin
username=root password=root
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值