阻塞和非阻塞

在介绍阻塞和非阻塞之前,我们先来了解一下多线程间一个重要的概念——临界区。

临界区——一种公有的资源或者共享数据,它可以被多个线程使用。临界区资源一次只能被一个线程使用,其它线程必须等待上一个线程
执行完成之后,才能使用。临界区资源是多线程之间重要保护对象,当临界区资源同时被多个线程访问时,容易出现错误。
代码示例:
 
  
/**
 * @author php
 * @date 2018/7/2
 */
public class CriticalRegion {
    //定义1000元
    public static Integer money = 1000;

    public static void main(String[] args) throws InterruptedException {
        //定义公共资源
        CriticalRegion criticalRegion = new CriticalRegion();
        //定义10个线程来购物
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        for (int i = 0; i < 10; i++) {
            executorService.execute(() -> {
                criticalRegion.shop();
            });
        }
        Thread.sleep(1000);
        System.out.println("最终还有:" + CriticalRegion.money);
        executorService.shutdown();
    }

    //我们每次购物使用100块钱
    public  void shop() {
        money = money - 100;
        System.out.println("使用了100元,我还有:" + CriticalRegion.money);
    }
}

执行结果:从中可以看出,多个线程,同时操作临界区资源时,容易导致操作资源错误。在大部分情况下,这是一个很严重的问题。
大家可以多执行几次,看看结果有什么不同。


现在,我们修改一下shop()方法,在方法上加上sychronized。执行结果:sychronized可以让临界区资源,一次只能被一个线程访问,

从而结果正确。


临界区资源,在使用多线程时,要格外的注意,以免结果千奇百怪。

在我们了解临界区之后,再来了解阻塞和非阻塞的概念。

阻塞和非阻塞通常被用来形容多线程间的相互影响。当一个线程占用了临界区资源,那么其它需要使用这个资源的线程都必须在这个临界区上等待。等待会导致线程挂起,这样就形成了阻塞。如果占用资源的线程一直没有释放资源,那么其它的线程在这个临界区上都不能继续工作。

相反,非阻塞表明多个线程之间的执行是不会相互影响的。

通常,我们使用synchronized关键字,ReentrantLock(重入锁)时,我们得到的线程就是阻塞线程。阻塞线程在执行代码前,都会尝试得到临界区资源的锁,如果得不到,线程就会一直挂起,直到临界区资源释放。

猜你喜欢

转载自blog.csdn.net/p_programmer/article/details/80891172