线程安全: 当多个线程同时共享,同一个全局变量或静态变量,做写的操作时,可能会发生数据冲突问题,也就是线程安全问题。
做读操作是不会发生数据冲突问题。
tips:
a、局部变量不存在线程安全问题
b、只有全局变量才会存在线程安全问题
解决线程安全思路
- 使用内置锁(synchronized)
- 显示锁(lock)
- CAS无锁机制
原理都是只能让当前一个线程进行执行。代码执行完成后释放锁,然后才能让其他线程进行执行。没有获取到锁的线程,则一直会排队阻塞,整个过程是一个悲观状态。
synchronized方式
//写操作
synchronized (res) {
//如果已经写完,没被读的话,则等待读取
if(res.writeFlg){
try {
res.wait();
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (count == 0) {
res.name = "老王";
res.sex = "男";
} else {
res.name = "小红";
res.sex = "女";
}
count = (count + 1) % 2;
//如果写完,则唤醒读
res.writeFlg = true;
res.notify();
}
//读操作
synchronized (res) {
//如果没有写,则等待先写
if(!res.writeFlg){
try {
res.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(res.name + "," + res.sex);
//读取完后,则设置为false,唤醒写程序
res.writeFlg = false;
res.notify();
}
Lock锁方式,不过wait和notify需要改为await和signal
public Lock lock = new ReentrantLock();
public Condition condition = lock.newCondition();
// 写操作
try {
res.lock.lock();
try {
if(res.writeFlg) {
res.condition.await();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
if (count == 0) {
res.name = "老王";
res.sex = "男";
} else {
res.name = "小红";
res.sex = "女";
}
count = (count + 1) % 2;
res.writeFlg = true;
res.condition.signal();
} finally {
res.lock.unlock();
}
// 读操作
try {
res.lock.lock();
try {
if(!res.writeFlg) {
res.condition.await();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(res.name + "," + res.sex);
res.writeFlg = false;
res.condition.signal();
} finally {
res.lock.unlock();
}
wait和notfiy的区别
Wait和notify是Object类的方法,主要做
a.Wait、Notify一定要在synchronized里面进行使用。
b.Wait必须暂定当前正在执行的线程,并释放资源锁,让其他线程可以有机会运行
c. notify/notifyall: 唤醒因锁池中的线程,使之运行
注意:一定要在线程同步中使用,并且是同一个锁的资源
wait和sleep的区别
a、wait()方法是Object类的,sleep是Thread类的
b、sleep()方法的过程中,线程不会释放对象锁。它只是暂停程序执行,让出CPU给其他线程调度,但监控依然保持,时间到了自动恢复运行。
wait()执行的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,只有调用此对象的notfiy才会进入运行状态
synchronized和lock锁的区别
Lock锁是JDK1.5之后新增的
a、Lock接口可以尝试非阻塞地获取锁(在截止时间到了依旧无法获取锁,则返回),而synchronize是阻塞地获取锁。
b、Lock锁需要手动获取锁和释放锁,synchronize释放锁的时间是未知的
一个自动挡一个手动挡
c、Lock锁使用AQS原理实现,synchronize使用监视器实现。
d、synchronized是使用wait和notify实现,Lock锁里面的LockSupport是使用pack和unpack实现。
LockSupport的pack/unpack与Synchronized的wait/notify区别?
Wait/notify存在interrupt的时候会中断不在执行。
Pack/unpack存在interrupt的时候会先执行结束,然后再执行中断。
相关文章链接:
<<<多线程基础
<<<锁的深入化
<<<锁的优化
<<<Java内存模型(JMM)
<<<Volatile解决JMM的可见性问题
<<<Volatile的伪共享和重排序
<<<CAS无锁模式及ABA问题
<<<Synchronized锁
<<<Lock锁
<<<AQS同步器
<<<Condition
<<<CountDownLatch同步计数器
<<<Semaphore信号量
<<<CyclicBarrier屏障
<<<线程池
<<<并发队列
<<<Callable与Future模式
<<<Fork/Join框架
<<<Threadlocal
<<<Disruptor框架
<<<如何优化多线程总结