当有多个线程设置对应的值的时候,读取的值是否是那个线程设置的值???如果我们单独对这个值上锁的话,情况会怎么样呢?
volatile Integer a = 0;
/**
* 当有多个线程设置对应的值的时候,读取的值是否是那个线程设置的值???
* 事实证明,单独上锁,并不能保证数据的唯一性,因为在部分线程在进行设置值的时候,我们并没有设置读锁
* 也就是说,这些线程读取的是之前的值,而不是线程阻塞设置的值
* 那么这种情况要怎么才能保证读写一致呢??读写锁。。。。
*/
@Test
public void test1() {
//设置栅栏,保证同时启动
CyclicBarrier cyclicBarrier = new CyclicBarrier(5);
for (int i = 1; i < 6; ++i) {
//每个线程获取并设置值
final int tmp = i;
new Thread(new Runnable() {
@Override
public void run() {
// System.out.println(Thread.currentThread().getName() + "准备:" + System.currentTimeMillis());
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
// System.out.println(Thread.currentThread().getName() + "开始:" + System.currentTimeMillis());
while (true) {
synchronized (a) {
// if (tmp == 5) {
// try {
// System.out.println(Thread.currentThread().getName() + "等待设置值:" + System.currentTimeMillis());
// Thread.sleep(4000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// }
a = tmp;
System.out.println(Thread.currentThread().getName() + "设置a值:" + a + "---" + System.currentTimeMillis());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// try {
// Thread.sleep(2000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
System.out.println(Thread.currentThread().getName() + "-read a =:" + a);
}
}
}).start();
}
while (true) {
int j = 1;
}
}
结果显示:
我们发现读取的a值杂乱无章,并不能保证是这个线程设置之后的值,为什么为这样呢???
因为我们只对a进行上锁的话,那么在对a进行设置值的时候,其他线程可以继续读取a的值,当a的值设置完毕之后,其他线程读取的值,我们也不知道是读取那个线程设置的值
如果我们把a设置为数据库的值的话,我们会发现,不通的人请求拿到的结果居然不是一样的
很简单举个例子:
A系统请求,需要获取某个地址信息的时候,B系统正在修改地址信息,那么在B修改完成之后,这个值还是可以读取的,只是不能被C系统修改而已
但是如果出现网络波动,或者业务逻辑比较复杂,那么就会导致B还没有修改完毕,A就把之前的旧数据读取过去了,这样就导致A系统用了一个错的地址信息,
结果就是地址错了,业务也就做错地方了,那么紧接着是不是就应该是投诉了!!!
那么这种情况要怎么才能保证读写一致呢??读写锁,在读的时候也要设置锁,保证B系统在修改数据的时候,其他系统无法读取
/**
* 这样就完全一致了。。。。
* 但是这个锁会导致效率极低,具体情境使用,看来还是要分情况啊
*/
@Test
public void test2() {
final ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();
//设置栅栏,保证同时启动
CyclicBarrier cyclicBarrier = new CyclicBarrier(5);
for (int i = 1; i < 6; ++i) {
//每个线程获取并设置值
final int tmp = i;
new Thread(new Runnable() {
@Override
public void run() {
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
while (true) {
//这里对变量a上写锁
reentrantReadWriteLock.writeLock().lock();
reentrantReadWriteLock.readLock().lock();
a = tmp;
System.out.println(Thread.currentThread().getName() + "设置a值:" + a + "---" + System.currentTimeMillis());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//读数据的时候,不允许读数据
reentrantReadWriteLock.readLock().unlock();
reentrantReadWriteLock.writeLock().unlock();
//这里上读锁
System.out.println(Thread.currentThread().getName() + "-read a =:" + a);
}
}
}).start();
}
while (true) {
int j = 1;
}
}
效果:
但是想必大家也发现问题了,那就是效率极低
但是如果数据是比较珍贵,核心的数据,这点效率的丢失是否值得就是需要权衡的东西了
Original: https://www.cnblogs.com/cutter-point/p/11949105.html
Author: cutter_point
Title: 【并发】10、当有多个线程设置对应的值的时候,读取的值是否是那个线程设置的值?
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/713242/
转载文章受原作者版权保护。转载请注明原作者出处!