- 悲观锁:一上来就加锁,没有安全感。每次只能一个线程进入访问完毕后,再解锁。 线程安 全,性能较差(因为锁竞争造成大量的线程阻塞和等待)!
- 乐观锁:一开始不上锁,认为是没有问题的,大家一起跑,等要出现线程安全问题的时候才 开始控制。线程安全,性能较好。
未加锁的代码:
package com.gch.lock;
/**
目标:学习悲观锁、乐观锁原理
*/
public class Test {
public static int number;
public static void main(String[] args) {
// 需求:1个静态变量,100个线程,每个线程对其加100次。
Runnable target = new MyRunnable();
for (int i = 0; i < 100; i++) {
new Thread(target).start();
}
}
}
package com.gch.lock;
public class MyRunnable implements Runnable{
// 记录浏览人次
private int count;
@Override
public void run() {
// 每个线程100次
for (int i = 0; i < 100; i++) {
// 每加一次,输出count
System.out.println("count=======>" + (++count));
}
}
}
注意:并不是每一次都会出现线程安全问题,这只是一个概率问题!
加悲观锁解决线程安全问题:
基于乐观锁解决线程安全问题: java.util.concurrent.atomic包下面的原子变量类
package com.gch.lock.test;
/**
目标:学习悲观锁、乐观锁原理
*/
public class Test {
public static int number;
public static void main(String[] args) {
// 程序多次运行可以发现,出现线程安全的概率还是很低的,并且哪怕出现线程安全问题===>9999
// 与我们的预期值只差1
// 说明100个线程在修改同一变量值的时候,也就是说10000次只出现了一次冲突,出现线程安全
// 问题的概率并不高
// 需求:1个静态变量,100个线程,每个线程对其加100次。
Runnable target = new MyRunnable();
for (int i = 0; i < 100; i++) {
new Thread(target).start();
}
}
}
package com.gch.lock.test;
import java.util.concurrent.atomic.AtomicInteger;
/**
又要线程安全,又要同时执行,就得用到乐观锁
*/
public class MyRunnable implements Runnable {
// 记录浏览人次
// 整数修改的乐观锁:原子类实现的
private AtomicInteger count = new AtomicInteger();
@Override
public void run() {
// 每个线程100次
for (int i = 0; i < 100; i++) {
// 每加一次,输出count
System.out.println(Thread.currentThread().getName() + "count=======>" +
(count.incrementAndGet())); // 方法内部是没有加锁的
}
}
}
incrementAndGet()方法源码解读: