美文网首页
并发编程基础小结-共享受限资源

并发编程基础小结-共享受限资源

作者: r09er | 来源:发表于2018-01-03 15:53 被阅读17次

在多线程中,最容易出现的问题就是资源冲突,多个线程试图同时操作一个对象或方法,就会导致很多意料之外的问题出现.

解决共享资源竞争

你永远不知道一个线程何时在运行.想象一下,你正在去夹起桌上的最后一块食物,当你将要夹起的时候,这块食物突然消失了,因为你的线程被挂起了,而另一个人进入并吃掉了他.这正是编写并发程序时需要处理的问题.防止这种冲突的方法就是当资源被一个任务使用时,在其加上锁.

基本上所有的并发模式在解决线程冲突问题的时候,都是采用序列化访问共享资源的方案,意味着同一时刻只允许一个任务访问共享资源.

Java平台提供的方案

  • 1 synchronized关键字是Java为防止资源冲突提供的内置支持,当执行被synchronized关键字修饰的代码片段时,它将检查锁是否可用,然后获取锁,执行代码,释放锁.保证在一定时间段内只有一个线程操作该方法.
    • i.对象锁synchronized(Object obj),持有不同锁之间的方法不会被阻塞.

如果使用synchronized(this),效果和方法锁是一样的,都会将整个类的所有同步方法都锁住直到释放锁

  • ii.方法锁修饰方法,synchronized method()

如果使用synchronized修饰方法,会将整个类的所有同步方法都锁住,因为使用的是当前类作为锁,只有当前一个方法调用完毕并释放了锁才能被调用

  • 2 使用显示Lock对象,与內建的锁形式相比,代码缺乏优雅性,但是如果操作出现了错误,可以在使用try-finally后将系统维护在正确的状态下.

Lock的使用一般都会配合try-finally,在finally中调用lock.unlock()释放锁.

示例代码

synchronized示例

定义多线程的执行方法,如果遇到不是偶数的情况就会停止

抽象类,定义公共方法

public abstract class IntGenerator {
    private volatile boolean canceled = false;
    public abstract int next();
    public void cancel(){
        canceled = true;
    }

    public boolean isCanceled() {
        return canceled;
    }
}

为了保证可视性canceled标记是volatile的(它修饰的变量每次被线程访问时都要从主存中重新读取该变量的值,并且当变量的值发生变化时会强迫线程刷新到主存中去),这就保证了canceled标记在被调用了一次之后就会马上变为true

多线程方法实现

public class EvenChecker implements Runnable {


    private IntGenerator generator;

    private final int id;

    public EvenChecker(IntGenerator generator, int id) {
        this.generator = generator;
        this.id = id;
    }

    @Override
    public void run() {
        while (!generator.isCanceled()) {
            int val = generator.next();
            if (val % 2 != 0) {
                System.out.println(val + " 不是偶数");
                generator.cancel();
            }
        }
    }

    public static void test(IntGenerator gp, int count) {
        System.out.println("Press Control-C to exit");
        ExecutorService executorService = Executors.newCachedThreadPool();
        for (int i = 0; i < count; i++) {
            executorService.execute(new EvenChecker(gp, i));
        }
        executorService.shutdown();
    }

加了方法锁的方法

public class  SynchronizedGenerator extends IntGenerator{

    private int currentEvenValue=0;

    @Override
    public synchronized int next() {
        ++currentEvenValue;

        Thread.yield();

        ++currentEvenValue;

        return currentEvenValue;
    }   
}

调用

 public static void main(String[] args) {
        EvenChecker.test(new SynchronizedGenerator());
    }

去掉synchronized后再观察输出

Lock示例

public class MutexEvenGenerator extends IntGenerator{

    private int currentEventValue = 0;

    private Lock lock = new ReentrantLock();

    @Override
    public int next() {
        lock.lock();
        try {
            ++currentEventValue;
            Thread.yield();
            ++currentEventValue;
            return currentEventValue;
        }finally {
            lock.unlock();
        }
    }
    
}

参考资料:Java编程思想

相关文章

  • 并发编程基础小结-共享受限资源

    在多线程中,最容易出现的问题就是资源冲突,多个线程试图同时操作一个对象或方法,就会导致很多意料之外的问题出现. 解...

  • SynChronized

    并发编程对共享资源,临界资源的访问 在并发编程中对临界资源的访问有可能出现并发问题,注意是临界资源,共享资源,普通...

  • 年薪50W阿里P7架构师必备知识:并发+JVM+多线程+Nett

    并发编程 线程基础、线程之间的共享和协作一 线程基础、线程之间的共享和协作二 线程的并发工具类 线程的并发工具类、...

  • 《JAVA并发编程的艺术》要点(一)并发编程的挑战

    并发编程的目的是为了让程序运行的更快 并发编程面临的挑战 一、上下文切换问题 二、死锁问题 三、资源受限问题 (一...

  • java内存模型

    java内存模型基础 并发编程,两个关键问题:线程通信和线程同步通信机制:共享内存和消息传递 java并发采用共享...

  • linux的并发和竞态管理

    1 并发和竞态产生的原因 并发是操作系统编程中的核心问题之一。我们必须要能解决对共享资源的并发访问。 并发产生资源...

  • 关于并发编程中临界资源的问题

    临界资源: 指并发环境中多个进程/线程共享的资源. 在并发编程中对临界资源的处理不当, 往往会导致数据不一致的问题...

  • Consul 之分布式锁

    锁的种类 在并发编程中,我们首先会学习到的知识点就是 锁 ,锁能够 简单有效 地解决并发编程中 共享资源竞争 的问...

  • java多线程(三)---资源限制

    1 什么是资源限制 资源限制是指在进行并发编程时,程序的执行速度受限于计算机硬件资源或软件资源。例如,服务器的带宽...

  • Java并发编程之CAS

    在Java并发编程的世界里,synchronized 和 Lock 是控制多线程并发环境下对共享资源同步访问的两大...

网友评论

      本文标题:并发编程基础小结-共享受限资源

      本文链接:https://www.haomeiwen.com/subject/mhvhnxtx.html