高并发,多线程开发的时候如何保证安全和程序的准确性?
初识Java内存模型与多线程
什么是不安全
当多个线程同时操作一个数据结构的时候产生了相互修改和串行的情况,没有保证数据的一致性,我们通常称这种设计的代码为“线程不安全的”。
有这么一个场景,假设5个用户,都来给一个数字加1的工作,那么最后应该是得到加5的结果:看一下下面的事例。
单个用户干活类:Count.
public class Count {
public int num=0;
public void add() {
try {
Thread.sleep(51);
}catch(InterruptedException e) {
}
num+=1;
System.out.println(Thread.currentThread().getName()+"-"+num);
}
}
用户类,干Count的活。
public class ThreadA_1 extends Thread {
private Count count;
public ThreadA_1(Count count) {
this.count=count;
}
@Override
public void run() {
// TODO Auto-generated method stub
count.add();
}
}
5个人干完活,最后的值
public class TestA_1 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Count count=new Count();
for(int i=0;i<5;i++) {
ThreadA_1 task=new ThreadA_1(count);
task.start();
}
try {
Thread.sleep(1001);
}catch(InterruptedException e) {
e.printStackTrace();
}
System.out.println("5个人干完活:最后的值是"+count.num);
}
}
运行结果,值可能是1,2,3,4,5中的任意一个
什么是安全
我们把上一节的例子单个用户干活类Count做如下修改,添加synchronized关键字。
public class Count {
public int num=0;
public synchronized void add() {
try {
Thread.sleep(51);
}catch(InterruptedException e) {
}
num+=1;
System.out.println(Thread.currentThread().getName()+"-"+num);
}
}
运行结果如下:
隐式锁,又称线程同步synchronized
显示锁Lock和ReentrantLock
显示锁ReadWriteLock和ReentrantReadWriteLock
实例体会:
第一种情况,先体验一下ReadLock和WriteLock单独使用的情况。
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class Test_2 {
public static void main(String[] args) {
final Count1 ct=new Count1();
for(int i=0;i<2;i++) {
new Thread() {
public void run() {
ct.get();
}
}.start();
}
for(int i=0;i<2;i++) {
new Thread() {
public void run() {
ct.put();
}
}.start();
}
}
}
class Count1{
private final ReentrantReadWriteLock rw1=new ReentrantReadWriteLock();
public void get() {
rw1.readLock().lock();
try {
System.out.println(Thread.currentThread().getName()+"read start.");
Thread.sleep(1000L);
System.out.println(Thread.currentThread().getName()+"read end.");
}catch(InterruptedException e) {
e.printStackTrace();
}finally{
rw1.readLock().unlock();
}
}
public void put() {
rw1.writeLock().lock();
try {
System.out.println(Thread.currentThread().getName()+"write start.");
Thread.sleep(1000L);
System.out.println(Thread.currentThread().getName()+"write end.");
}catch(InterruptedException e) {
e.printStackTrace();
}finally{
rw1.writeLock().unlock();
}
}
}
运行结果:
第二种情况,我们体会一个ReadLock和WriteLock的复杂使用情况,模拟一个有读写数据的场景,仔细体会一下
显示锁StampedLock
什么是死锁
Java关键字volatile修饰变量
原子操作atomic