实现一个简单的线程安全的数字自增方法
public class CountNumImpl {
//定义 ReentrantLock 锁
private static ReentrantLock reentrantLock = new ReentrantLock();
//自增数
private static int num = 0;
/**
* 使用lock 的自增方法
*/
public static void autoCountNum() {
//获得锁(加锁)
reentrantLock.lock();
try {
//执行业务方法 todo
num++;
System.out.println("线程名:"+Thread.currentThread().getName()+";当前数为:"+ num);
}finally {
//finally 块内总是 释放掉锁
reentrantLock.unlock();
}
}
//main 方法执行
public static void main(String[] args) {
//通过循环创建 10个线程,一起去调用 自增方法
for (int i = 0; i < 10; i++) {
new Thread(new Runnable() {
@Override
public void run() {
autoCountNum();
}
}).start();
}
}
}
执行结果:
线程名:Thread-1获取到锁执行自增,当前数为:1
线程名:Thread-2获取到锁执行自增,当前数为:2
线程名:Thread-0获取到锁执行自增,当前数为:3
线程名:Thread-7获取到锁执行自增,当前数为:4
线程名:Thread-4获取到锁执行自增,当前数为:5
线程名:Thread-9获取到锁执行自增,当前数为:6
线程名:Thread-8获取到锁执行自增,当前数为:7
线程名:Thread-3获取到锁执行自增,当前数为:8
线程名:Thread-5获取到锁执行自增,当前数为:9
线程名:Thread-6获取到锁执行自增,当前数为:10
开始探索:
-
lock 方法:获取锁;
当Thread-1 在执行 lock 方法时未获得锁,则 Thread-1会一直阻塞直到获取锁;
例如:在自增后设置线程休眠3秒
再次执行后还是会在每次自增后间隔3秒继续打印; -
tryLock 方法:尝试获取锁;
拿到锁后返回true,未拿到锁则直接返回false,不会进行阻塞/等待。(有参的 tryLock 方法可以设置等待/阻塞时间,即在等待时间内能拿到锁则返回 true,拿不到则返回false )
示例:无参的 unLock 方法;
/**
* 使用 unLock 的自增方法
*/
public static void autoCountNumByUnlock() {
//尝试获得锁(加锁)
boolean b = reentrantLock.tryLock();
if(!b){
System.out.println("线程名:"+Thread.currentThread().getName()+"未获取到锁,不执行自增!");
return;
}
try {
//执行业务方法 todo
num++;
System.out.println("线程名:"+Thread.currentThread().getName()+"获取到锁执行自增,当前数为:"+ num);
}finally {
//finally 块内总是 释放掉锁
reentrantLock.unlock();
}
}
执行结果:(可以多执行几遍观察一下)
线程名:Thread-1未获取到锁,不执行自增!
线程名:Thread-0获取到锁执行自增,当前数为:1
线程名:Thread-2未获取到锁,不执行自增!
线程名:Thread-3未获取到锁,不执行自增!
线程名:Thread-6未获取到锁,不执行自增!
线程名:Thread-4获取到锁执行自增,当前数为:2
线程名:Thread-5获取到锁执行自增,当前数为:3
线程名:Thread-7未获取到锁,不执行自增!
线程名:Thread-8获取到锁执行自增,当前数为:4
线程名:Thread-9获取到锁执行自增,当前数为:5
再在自增后设置线程休眠3秒
执行结果:(可以多执行几遍观察一下)
线程名:Thread-1未获取到锁,不执行自增!
线程名:Thread-3未获取到锁,不执行自增!
线程名:Thread-4未获取到锁,不执行自增!
线程名:Thread-2未获取到锁,不执行自增!
线程名:Thread-7未获取到锁,不执行自增!
线程名:Thread-0获取到锁执行自增,当前数为:1
线程名:Thread-8未获取到锁,不执行自增!
线程名:Thread-6未获取到锁,不执行自增!
线程名:Thread-5未获取到锁,不执行自增!
线程名:Thread-9未获取到锁,不执行自增!
示例:有参的tryLock;
/**
* 使用 unLock 的自增方法
*/
public static void autoCountNumByUnlock() {
//尝试获得锁(加锁)
boolean b = false;
try {
//设置获得锁(自旋)的时间
b = reentrantLock.tryLock(5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(!b){
System.out.println("线程名:"+Thread.currentThread().getName()+"未获取到锁,不执行自增!");
return;
}
try {
//执行业务方法 todo
num++;
System.out.println("线程名:"+Thread.currentThread().getName()+"获取到锁执行自增,当前数为:"+ num);
//休眠3秒
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}finally {
//finally 块内总是 释放掉锁
reentrantLock.unlock();
}
}
执行结果:(可以多执行几遍观察一下)
线程名:Thread-0获取到锁执行自增,当前数为:1
线程名:Thread-2获取到锁执行自增,当前数为:2
线程名:Thread-3未获取到锁,不执行自增!
线程名:Thread-4未获取到锁,不执行自增!
线程名:Thread-5未获取到锁,不执行自增!
线程名:Thread-7未获取到锁,不执行自增!
线程名:Thread-6未获取到锁,不执行自增!
线程名:Thread-1未获取到锁,不执行自增!
线程名:Thread-8未获取到锁,不执行自增!
线程名:Thread-9未获取到锁,不执行自增!