悲观锁:
一上来就加锁,没有安全感,每次只能一个线程进入访问完毕后,再解锁。 线程安全,性能较差
乐观锁:
一开始不上锁,认为是没有问题的,大家一起跑,等要出现线程安全问题的时候才开始控制。 线程安全,性能较好
接下来我们通过案例,来分别实现三种情况:1、不加锁的情况,2、加悲观锁 3、加乐观锁。我们创建两个类来进行案例的演示,分别是Test类和MyRunnable类。
MyRunnable类
package ThreadTzTest;
public class MyRunnable implements Runnable{
private int count;//记录浏览人数
@Override
public void run() {
//100次
for (int i = 0; i < 100; i++) {
System.out.println("count======>"+(++count));
}
}
}
Test类
package ThreadTzTest;
public class Test {
public static void main(String[] args) {
//目标:拓展悲观锁、乐观锁原理
//悲观锁:一上来就加锁,没有安全感,每次只能一个线程进入访问完毕后,再解锁。 线程安全,性能较差
//乐观锁:一开始不上锁,认为是没有问题的,大家一起跑,等要出现线程安全问题的时候才开始控制。 线程安全,性能较好
//需求:1个静态变量,100个线程,每个线程对其加100次
Runnable target = new MyRunnable();
for (int i = 1; i <= 100; i++) {
new Thread(target).start();
}
}
}
运行结果:
可以看到结果是不正确的,正确结果应该是10000,这是因为出现了线程安全问题。
MyRunnable类
package ThreadTzTest;
public class MyRunnable implements Runnable{
private int count;//记录浏览人数
@Override
public void run() {
//100次
synchronized (this) {
for (int i = 0; i < 100; i++) {
System.out.println("count======>"+(++count));
}
}
}
}
Test类不变,我们再来看运行结果:
可以看到,添加悲观锁后线程正确运行了,没有出现线程安全问题。
package ThreadTzTest;
import java.util.concurrent.atomic.AtomicInteger;
public class MyRunnable2 implements Runnable{
//整数修改的乐观锁,原子类实现的
private AtomicInteger count = new AtomicInteger();
@Override
public void run() {
//100次
for (int i = 0; i < 100; i++) {
System.out.println("count======>"+count.incrementAndGet());
//incrementAndGet()先加1再返回,在方法的内部没有加锁
}
}
}
package ThreadTzTest;
public class Test {
public static void main(String[] args) {
//目标:拓展悲观锁、乐观锁原理
//悲观锁:一上来就加锁,没有安全感,每次只能一个线程进入访问完毕后,再解锁。 线程安全,性能较差
//乐观锁:一开始不上锁,认为是没有问题的,大家一起跑,等要出现线程安全问题的时候才开始控制。 线程安全,性能较好
//需求:1个静态变量,100个线程,每个线程对其加100次
Runnable target = new MyRunnable2();
for (int i = 1; i <= 100; i++) {
new Thread(target).start();
}
}
}
运行结果:
乐观锁实现原理:
先存下原来的值是多少,然后进行数据的操作,进行修改的时候判断存下来的值和现在的值是否相等,如果相等就把修改后的数据存进去
public class OptimisticLock {
private int version;
private String data;
public String readData() {
return data;
}
public boolean updateData(String newData) {
int currentVersion = version;
// 更新数据
data = newData;
version++;
// 检查版本号是否一致
if (currentVersion != version) {
// 版本号不一致,回滚事务
return false;
}
// 提交事务
return true;
}
}