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

2018-01-03  本文已影响17人  r09er

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

解决共享资源竞争

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

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

Java平台提供的方案

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

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

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

上一篇下一篇

猜你喜欢

热点阅读