一.悲观锁
有Synchronized关键字的被称为悲观锁
二.乐观锁
CAS 机制 :compare and swap 比较和交换
如果多个线程要访问一个静态的成员变量:Synchronized会把这个静态
的成员变量锁住,其他线程就访问不了,必须等到拿到这个锁的线程解开锁,
其他线程才能继续访问。而CAS则不会给这个静态的成员变量加锁,而是做
一个尝试,先拿到旧值,查看旧值是否与共享区域的值相等,如果不等,就说明
别的线程改动了共享区域的值,修改失败。如果相等,就修改成功,如果修改失败
还会继续尝试。
代码展示:int var5;
// 修改失败,没关系,重新尝试 自旋
do {
// 获取共享区域的最新值
var5 = this.getIntVolatile(var1, var2); // 10
// 比较并交换 最新值 最新值+1
} while(! this.compareAndSwapInt(var1, var2, var5, var5 + var4));
return ar5;
1.重入锁 ReentrantLock
lock()加锁
unlock()解锁
代码展示:
//重入锁
public class Demo1 {
static int i = 0;
public static void main(String[] args) throws InterruptedException {
ReentrantLock ret = new ReentrantLock();
Thread thread1 = new Thread(() -> {
for (int j = 0; j < 5000; j++) {
try {
ret.lock();
i--;
} finally {
ret.unlock();
}
}
});
thread1.start();
Thread thread = new Thread(() -> {
for (int j = 0; j < 5000; j++) {
try {
ret.lock();
i++;
} finally {
ret.unlock();
}
}
});
thread.start();
thread.join();
thread1.join();
System.out.println(i);
}
}
注意:synchronized 性能上比较 ReentrantLock 在高并发下低,ReentrantLock的内存占用会高一些
2.倒计时 CountDownLatch
当希望多个线程执行完毕之后,在接着做下一步的操作
代码展示:
//倒计时锁
public class Demo {
public static void main(String[] args) throws InterruptedException {
CountDownLatch cdl = new CountDownLatch(3);
new Thread(() -> {
System.out.println("线程一开始");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程一结束");
cdl.countDown();
}).start();
new Thread(() -> {
System.out.println("线程二开始");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程二结束");
cdl.countDown();
}).start();
new Thread(() -> {
System.out.println("线程三开始");
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程三结束");
cdl.countDown();
}).start();
cdl.await();
System.out.println("继续执行剩余的程序");
}
}
倒计时锁:模拟英雄联盟十个玩家进入游戏的进度条
//倒计时锁,模拟游戏中的玩家进入游戏的过程
public class Demo2 {
public static void main(String[] args) throws InterruptedException {
CountDownLatch cdl = new CountDownLatch(10);
String[] s = new String[10];
for (int i = 0; i < 10; i++) {
int x = i;
new Thread(() -> {
Random random = new Random();
for (int j = 0; j <= 100; j++) {
try {
Thread.sleep(random.nextInt(100));
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (cdl) {
s[x] = j + "%";
System.out.print("\r" + Arrays.toString(s));
}
}
cdl.countDown();
}).start();
}
cdl.await();
System.out.printl("继续执行剩余的程序");
}
}
3.信号量 Semaphore
代码展示:
//Semaphore 信号量
public class Demo4 {
public static void main(String[] args) {
Semaphore ssp = new Semaphore(2);
for (int i = 0; i < 20; i++) {
new Thread(() -> {
try {
ssp.acquire();
System.out.println(Thread.currentThread().getName() + "我就是这个线程");
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
ssp.release();
}
}).start();
}
}
}
4.循环栅栏 CyclicBarrier
当满足CyclicBarrier设置的线程个数时,继续执行,没有满足则等待
代码展示:
//CyclicBarrier 可循环的 屏障(栅栏)
public class Demo3 {
public static void main(String[] args) {
CyclicBarrier clb = new CyclicBarrier(3); //有三个线程的时候才开始运行
new Thread(()->{
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
clb.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println("我是第一个线程");
}).start();
new Thread(()->{
try {
clb.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}).start();
System.out.println("我是第二个线程");
new Thread(()->{
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
clb.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println("是第三个线程");
}).start();
}
}
与倒计时锁的区别:倒计时锁只能使用一次,倒计时结束这个对象就没用了。
而循环栅栏可以重复利用。
线程中的悲观锁和乐观锁
猜你喜欢
转载自blog.csdn.net/woshijinfeixi/article/details/81836507
今日推荐
周排行