线程中的悲观锁和乐观锁

一.悲观锁
    有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