对于java线程安全问题感兴趣的读者,本文将会是一篇不错的选择,我们将详细介绍java线程安全问题如何查,并为您提供关于02、线程安全问题、6.ArrayList线程安全问题、Android开发——线
对于java 线程安全问题感兴趣的读者,本文将会是一篇不错的选择,我们将详细介绍java线程安全问题如何查,并为您提供关于02、线程安全问题、6.ArrayList 线程安全问题、Android开发——线程安全问题、asp.net – HMACSHA1.ComputeHash()线程安全问题的有用信息。
本文目录一览:- java 线程安全问题(java线程安全问题如何查)
- 02、线程安全问题
- 6.ArrayList 线程安全问题
- Android开发——线程安全问题
- asp.net – HMACSHA1.ComputeHash()线程安全问题
java 线程安全问题(java线程安全问题如何查)
java线程安全的处理我知道的现在就2种比如我有这样一个对象
public class User { private int id; private String name; private int money; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getMoney() { return money; } public void setMoney(int money) { this.money = money; } }
public class UserDao { public User getById(int id){ ... } public User getByType(int type){ ... } }
为何synchronized不起作用呢?下面代码解释
public class A_Thread implements Runnable{ public void run() { //此时查询出来的数据是原数据的一个clone 原数据再怎么变这个对象也不会受影响 User user = UserDao.getById(1); Thread.sleep(1000); user.setMoney(user.getMoney()+10); user.update(); } } public class B_Thread implements Runnable{ public void run() { //此时查询出来的数据是原数据的一个clone 原数据再怎么变这个对象也不会受影响 User user = UserDao.getById(1); Thread.sleep(1000); user.setMoney(user.getMoney()+10); user.update(); } } public class Test{ public static void main(String[] agrs){ ExecutorService exe = Executors.newFixedThreadPool(8); exe.execute(new A_Thread()); exe.execute(new B_Thread()); } }
public static void main(String[] agrs){ User user = UserDao.getById(1); int money = user.getMoney(); money = ??? }
结果这个user的 值根本确定不了 无论在那加 synchronized
public synchronized int getMoney() { return money; } public synchronized void setMoney(int money) { this.money = money; }
到这大概有人会说把User保留一分在内存中,查询始终,修改始终都是操作的内存中这个User对象!
但会有以下几个问题
1.数据会出出现完整性问题(多线程并发的时候 你一个逻辑线程需要set 10属性,但才3个,另外一个逻辑线程要取这个对象,那个瞬间他取过去的数据实际上就只改了3个属性)
2.如果我set了 但是update失败!但是内存中的数据任然有部分已经受到了影响
好了!synchronized不能很好的解决我的问题,那么我就来用Lock。Lock必须显示的加锁和放锁
我要防止上面的问题,在比如getById()的时候就有了2中加锁方式,加读锁和写锁。我需要修改的查询就在调用getById中加上写锁,只读不修改的时候就加读锁。而现在问题又来了
并且我是加在User的实例对象上的,加载Dao也可以但性能会底很多!
1.我加了写锁之后必须等我逻辑线程处理完后 简单的说就是要 update之后才能放锁!
2.如果逻辑线程在取得写锁后逻辑出现异常了!导致没有换锁!
解决这个我的处理试了一下几种
1.加了个最大持有该锁的时间,当另外一个线程要获得该锁的时候检查时间,如果超过时间,中断持有改锁的线程(不大友好)
2.定时检查,但并发高的时候会有很多定时器
3.改造getById(int id)方法,getById(int id,List<Lock> locks) 在查询中传一个List进去,把该次操作的的Lock反馈出来,在逻辑处理完后全部释放!
List<Lock> locks = new ArrayList(); try { //业务逻辑 getById(1,locks); } catch (Exception e) { }finally{ //locks 全部释放掉 }
02、线程安全问题
CAS存在的问题:
1、循环+CAS,自旋的实现让所有线程处于高频运行,争抢cpu执行时间的状态。如果操作长时间不成功,会带来很大的cpu资源消耗。
2、仅针对单个变量操作,不能用于多个变量来实现原子性操作。
3、ABA问题。(可以加上版本号机制予以解决)
6.ArrayList 线程安全问题
转:
6.ArrayList 线程安全问题
题出问题
我们知道 ArrayList 是线程不安全,请编写一个不安全的案例并给出解决方案?
单线程环境
单线程环境的 ArrayList 是不会有问题的
public class ArrayListNotSafeDemo {
public static void main(String[] args) {
List
list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
for(String element : list) {
System.out.println(element);
}
}
}
多线程环境
为什么多线程环境下 ArrayList 是线程不安全的?因为在进行写操作(add 方法)的时候,方法上为了保证并发性,没有添加 synchronized 修饰。
当我们同时启动 30 个线程去操作 List 的时候
public class Test {
public static void main(String[] args) {
List
list = new ArrayList<>();
for (long i = 0; i < 30; i++) {
new Thread(() -> {
list.add("hello");
list.add("world");
list.add("java");
System.out.println(list);
}).start();
}
}
}
我们运行发现报了 java.util.ConcurrentModificationException(并发修改的异常)
解决方案
方案一:Vector
采用 Vector 实现线程安全,Vector 在方法上加了锁,即 synchronized
这样就每次只能够一个线程进行操作,所以不会出现线程不安全的问题,但是因为加锁了,导致并发性下降。
方案二:Collections.synchronized ()
List
list = Collections.synchronizedList(new ArrayList<>());
采用 Collections 集合工具类,在 ArrayList 外面包装一层 同步 机制
方案三:采用 JUC 里面的方法
CopyOnWriteArrayList:写时复制,主要是一种读写分离的思想。
- 就是写的时候,把 ArrayList 扩容一个出来,然后把值填写上去,在通知其他的线程,ArrayList 的引用指向扩容后的。
CopyOnWriteArrayList
list = new CopyOnWriteArrayList<>();
查看 add 方法源码
首先需要加锁
final ReentrantLock lock = this.lock; lock.lock();
然后在末尾扩容一个单位
Object[] elements = getArray(); int len = elements.length; Object[] newElements = Arrays.copyOf(elements, len + 1);//扩容一个单位,复制到新数组
然后在把扩容后的空间,填写上需要 add 的内容
newElements[len] = e;
- 最后把内容 set 到 Array 中
应用场景:一般用于黑 / 白名单,这样的地方,标准的读多写少场景
HashSet 线程不安全
用 CopyOnWriteArraySet
(底层还是用的 CopyOnWriteArrayList)
HashMap 线程不安全
- 使用
Collections.synchronizedMap(new HashMap<>())
使用 ConcurrentHashMap
Map
map = new ConcurrentHashMap<>();
转:
6.ArrayList 线程安全问题
--Posted from Rpc
Android开发——线程安全问题
死锁
产生的原因:
- 多个操作者争夺多个资源(操作者>资源数>=2)
- 拿到资源不放手
- 争夺资源的顺序不对
危害:
- 线程不工作了,但是整个程序还是活着的
- 没有任何的异常信息可以供我们检查
- 一旦程序发生了发生了死锁,是没有任何的办法恢复的,只能重启程序,对正式已发布程序来说,这是个很严重的问题。
解决方式:
- 调整拿锁的顺序,采用尝试拿锁机制(tryLock)。
- 内部通过顺序比较,确定拿锁的顺序。
活锁
两个线程在尝试拿锁的机制中,发生多个线程之间互相谦让,不断发生同一个线程总是拿到同一把锁,在尝试拿另一把锁时因为拿不到,而将本来已经持有的锁释放的过程。
解决办法:每个线程休眠随机数,错开拿锁的时间。
线程饥饿
低优先级的线程,总是拿不到执行时间
asp.net – HMACSHA1.ComputeHash()线程安全问题
all(HMACSHA1)instance-和ComputeHash() – 由ComputeHash()使用/修改的方法变量将被所有线程共享(=可以修改)?这个假设是正确的吗?
因此,ComputeHash的返回值不能保证是正确的?!?!
因此我不允许在所有的asp.net-threads上使用静态/共享HMACSHA1实例.
我只是想知道你对这个问题的看法.
解决这个问题的唯一方法就是在ComputeHash()方法中使用关键路径等.但那是“我们无法接触到的”..
问候,
短剑的一种
解决方法
只要您每次使用相同的密钥,就不需要将它们设置为静态.但是,如果您使用无参数构造函数构造HMACSHA1实例,则它会生成随机密钥.您应该从keyvalue属性中获取随机值并将其与散列一起存储.
使用静态实例肯定是危险的.如果Thread1设置要计算的值,然后Thread2在Thread1调用ComputerHash()之前设置该值,则Thread1将获取Thread2值的散列值.如果任一线程正在设置密钥,则会发生相同的情况.
关于java 线程安全问题和java线程安全问题如何查的介绍现已完结,谢谢您的耐心阅读,如果想了解更多关于02、线程安全问题、6.ArrayList 线程安全问题、Android开发——线程安全问题、asp.net – HMACSHA1.ComputeHash()线程安全问题的相关知识,请在本站寻找。
本文标签: