认识java中线程安全问题
来源:互联网 发布:mysql 查看表锁情况 编辑:程序博客网 时间:2024/05/17 08:45
出现场景: 多个线程同时操作一个对象,如果该对象没有线程安全的控制,便会出现线程安全问题。例如:我们有一个类A
public class A{ int count=0; public void add1000(){ for(int i=0;i<1000;i++){ count++; System.out.println(count); } }}
如上代码所示,A中有一个成员变量count,有一个让count加1000的方法,并打印。如果声明A一个对象,一个线程访问没问题,会从打印0~999。但当多个线程操作A的同一个对象,就可能发生一个现象:
public static void main(String[] args) { Run run = new Run(); new Thread(new Runnable() { @Override public void run() { run.add1000("A"); } }).start(); new Thread(new Runnable() { @Override public void run() { run.add1000("B"); } }).start(); }
从上面的代码可以看到,启动了两个线程,每个线程都只是想让A的count打印从0到999,但由于线程之间的运行方式是轮着运行的(对线程运行方法不了解,可自行搜索学习),会导致这两个线程都操作count,count的值也是在一直变的,就不能保证add1000这个方法的原子性。
解决办法: 对于解决办法,java特别提供了保证线程安全的类和关键字,同时java的类中也有好多是线程安全和不安全两个版本。
首先最简单的解决办法就是使用synchronized关键字
public synchronized void add1000(String s) { for (int i = 0; i < 1000; i++) { count++; System.out.println(s + count); } }
在add1000方法前添加synchronized关键字便可保证该方法变成线程安全的,原理大概是,当某个线程调用此方法时,会获取该实例的对象锁,方法未结束之前,其他线程只能去等待。当这个方法执行完时,才会释放对象锁。其他线程才有机会去抢占这把锁,去执行该方法。同时该关键字也能同步代码块。
使用Lock类;lock是java concurrent包下的一个类,该类可以很自由的给任意代码段添加锁及释放锁。
public static void main(String[] args) { Lock lock = new ReentrantLock(); Run run = new Run(lock); new Thread(new Runnable() { @Override public void run() { run.add1000("A"); } }).start(); new Thread(new Runnable() { @Override public void run() { run.add1000("B"); } }).start(); } public static class Run { int count = 0; Lock lock; public Run(Lock lock){ this.lock=lock; } // count加1000 public synchronized void add1000(String s) { for (int i = 0; i < 1000; i++) { try{ lock.lock(); count++; System.out.println(s + count); }finally{ lock.unlock(); } } } }
如上代码便是使用Lock进行加锁,如果你把finally的释放锁代码注释掉,第二个线程就无法执行该,程序一直卡在这,因为线程一一直持有该段代码的锁,线程二一直等待获取锁,便发生了死锁堵塞。
0 0
- 认识java中线程安全问题
- java 集合中线程安全问题
- Java中线程的安全问题
- JAVA中关于线程通信安全问题
- Java中线程安全问题个人理解
- Java中线程安全问题个人理解
- java中final与volatile-线程安全问题
- Java线程安全问题
- java线程安全问题笔记
- java线程编程安全问题
- java之线程安全问题
- java线程安全问题
- 关于java线程安全问题
- Java-线程安全问题
- Java 多线程 线程安全问题
- Java-----Servlet线程安全问题
- Java中线程的创建使用及其安全问题
- Struts1中action线程安全问题
- ZooKeeper介绍
- 代理模式
- struts2结果类型
- Eclipse中替换变量
- Yocto
- 认识java中线程安全问题
- 利用Python下载文件
- 关于腾讯通(RTX)服务器端和客户端的安装设置及其报错
- 谈谈对Spring IOC的理解
- java异常处理
- Android应用间通讯和数据共享
- 从键盘上输入任意的正整数,编程判断该数是否为回文数。 所谓的回文数就是从左到右读这个数与从右到左读这个数是一样的。 例如,12321 , 4004都是回文数。
- hdu 1754 I hate it (线段树)
- C#6.0 新新特性