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

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

作者: 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编程思想

    相关文章

      网友评论

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

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