`

Java内容的复习-lock和condition的使用

 
阅读更多

以前遇到一个面试题,一些农民往桶里放苹果,一些农民往桶里面拿苹果,当桶达到1000个苹果的时候不能再放了,当桶的个数少于5个的时候不能再拿了。这个例子用lock和condition可以很好的解决。condition有await方法和signal方法,当调用await方法的时候,会释放当前的锁,然后将当前线程放到condition的等待队列中。当调用signal方法时,会调用将condition等待队列中的第一个线程放到sync队列中,那样那个线程就可以继续竞争锁。Condition和object的wait,notify方法的区别是,同一个锁可以有多个条件控制。而object的wait方法则不能。

import sun.misc.Unsafe;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created by Administrator on 8/3/14.
 */
public class Bucket<T> {
    private List<T> cache = new ArrayList<T>();
    private ReentrantLock lock = new ReentrantLock();
    private Condition putCondition = lock.newCondition();
    private Condition getCondition = lock.newCondition();
    private int capacity = 1000;
    private int minSize = 5;

    public Bucket(int capacity, int minSize) {
        if(minSize >= capacity){
            throw new IllegalArgumentException("capacity must large than minSize!");
        }
        this.capacity = capacity;
        this.minSize = minSize;
    }

    public void put(T object){
        try{
            lock.lock();
            while (cache.size() == capacity){
                putCondition.await();
            }

            cache.add(object);
            getCondition.signal();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }

    public T get(){
        T value = null;
        try{
            lock.lock();
            while (cache.size() <= minSize){
                getCondition.await();
            }
            System.out.println("Cache size:" + cache.size());

            value = cache.remove(0);
            putCondition.signal();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
        return value;
    }

    static class Apple{
        public String getKey() {
            return key;
        }

        public void setKey(String key) {
            this.key = key;
        }

        private String key;

        Apple(String key) {
            this.key = key;
        }
    }

    static class Provider implements Runnable{
        private Bucket<Object> bucket;
        private String name;

        public Provider(Bucket<Object> bucket,String name) {
            this.bucket = bucket;
            this.name = name;
        }

        @Override
        public void run() {
            int index = 1;
            while (true){
                Apple apple = new Apple(name + "-" + index++);
                bucket.put(apple);
                System.out.println("Add apple " + apple.getKey() + " to bucket");
            }
        }
    }


    static class Consumer implements Runnable{
        Bucket<Object> bucket;

        public Consumer(Bucket<Object> bucket) {
            this.bucket = bucket;
        }

        @Override
        public void run() {
            while (true){
                Apple apple = (Apple) bucket.get();
                System.out.println("Get apple " + apple.getKey() + " from bucket");
            }
        }
    }

    public static void main(String[] args){
        Bucket<Object> bucket = new Bucket<Object>(100,5);
        for(int i =0;i < 2;i++){
            new Thread(new Provider(bucket,"Provider" + i)).start();
        }

        for(int i =0;i < 5;i++){
            new Thread(new Consumer(bucket)).start();
        }
    }
}

    改进版,put和take可以同时运行。模拟LinkedBlockQueue

/**
 * Created by Administrator on 8/10/14.
 */

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sun.misc.Unsafe;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created by Administrator on 8/3/14.
 */
public class BucketEx<T> {
    static Logger logger = LoggerFactory.getLogger(BucketEx.class);
    private ReentrantLock takeLock = new ReentrantLock();
    private ReentrantLock putLock = new ReentrantLock();
    private Condition notFull = putLock.newCondition();
    private Condition notEmpty = takeLock.newCondition();
    private Node<T> head, tail;

    private AtomicInteger count = new AtomicInteger(0);
    private int capacity = 1000;
    private int minSize = 5;

    class Node<T> {
        Node<T> next;
        T item;

        Node(T item) {
            this.item = item;
        }
    }

    public BucketEx(int capacity, int minSize) {
        if (minSize >= capacity) {
            throw new IllegalArgumentException("capacity must large than minSize!");
        }
        this.capacity = capacity;
        this.minSize = minSize;
        head = tail = new Node<T>(null);
    }

    public T dequeue() {
        Node h = head;
        Node<T> first = h.next;
        h.next = h;

        T item = first.item;
        first.item = null;
        head = first;
        return item;
    }

    public void enqueue(T item) {
        tail = tail.next = new Node<T>(item);
    }

    public void signalNotEmpty() {
        takeLock.lock();
        try{
            notEmpty.signal();
        }finally {
            takeLock.unlock();
        }
    }


    public void signalNotFull() {
        putLock.lock();
        try{
            notFull.signal();
        }finally {
            putLock.unlock();
        }
    }

    public void put(T object) throws InterruptedException {
        putLock.lockInterruptibly();
        int c = -1;
        try {
            while (count.get() >= capacity) {
                notFull.await();
            }

            enqueue(object);
            c = count.getAndIncrement();
            logger.info("put " + object.toString() + " size" + c);            
            if (c < capacity) {
                notFull.signal();
            }
        }finally {
            putLock.unlock();
        }

        if (c == minSize) {
            signalNotEmpty();
        }
    }

    public T get() throws InterruptedException {
        T item = null;
        takeLock.lockInterruptibly();
        int c = -1;

        try {
            while (count.get() <= minSize) {
                notEmpty.await();
            }

            item = dequeue();
            c = count.getAndDecrement();
            logger.info("take " + item.toString() + " size" + c);
            if (c > minSize) {
                notEmpty.signal();
            }
        } finally {
            takeLock.unlock();
        }

        if (c == capacity) {
            signalNotFull();
        }
        return item;
    }

    static class Apple {
        public String getKey() {
            return key;
        }

        public void setKey(String key) {
            this.key = key;
        }

        private String key;

        Apple(String key) {
            this.key = key;
        }

        @Override
        public String toString() {
            return "Apple{" +
                    "key='" + key + '\'' +
                    '}';
        }
    }

    static class Provider implements Runnable {
        private BucketEx<Object> bucket;
        private String name;

        public Provider(BucketEx<Object> bucket, String name) {
            this.bucket = bucket;
            this.name = name;
        }

        @Override
        public void run() {
            int index = 1;
            while (true) {
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Apple apple = new Apple(name + "-" + index++);
                try {
                    bucket.put(apple);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    static class Consumer implements Runnable {
        BucketEx<Object> bucket;
        String name;

        public Consumer(BucketEx<Object> bucket,String name) {
            this.bucket = bucket;
            this.name = name;
        }

        @Override
        public void run() {
            while (true) {
                try {
                    Apple apple = (Apple) bucket.get();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        BucketEx<Object> bucket = new BucketEx<Object>(1000, 5);
        for (int i = 0; i < 1; i++) {
            new Thread(new Provider(bucket, "Provider" + i), "Provider" + i).start();
        }

        Thread.sleep(10000);
        for (int i = 0; i < 5; i++) {
            new Thread(new Consumer(bucket,"Customer" + i),"Customer" + i).start();
        }
    }
}

 

分享到:
评论

相关推荐

    Java-Interview-超全集合github上评分最高的jiva面试题

    - **同步机制**:synchronized关键字、Lock接口(ReentrantLock、Condition)的使用,以及死锁的概念。 - **并发容器**:如ConcurrentHashMap、BlockingQueue、ThreadPoolExecutor等在多线程环境下的应用。 4. **...

    java复习文档,含.md程序

    Java是世界上最流行的编程语言之一,尤其在企业级应用开发领域占据主导地位。本文将深入探讨Java中的并发和...Java复习笔记中应该涵盖了这些内容的详细解释和实例,通过深入学习,你可以进一步巩固和提升自己的技能。

    java并发源码-java-concurrent-test:和朱晔一起复习Java并发系列文章

    2. **并发控制**:Java提供了多种并发控制工具,如`synchronized`关键字、`wait()`/`notify()`、`Lock`接口(包括`ReentrantLock`可重入锁)及其相关的`Condition`条件对象。 3. **原子操作**:`java.util....

    JAVA复习资料

    这份“JAVA复习资料”显然旨在帮助学习者巩固和提升Java编程技能,为备考或者项目开发提供支持。下面,我们将深入探讨Java的核心概念和技术。 一、Java基础 1. 类与对象:Java是一种面向对象的语言,类是对象的模板...

    Java语言程序设计第8版 例题源码+习题源码+复习题源码.rar

    《Java语言程序设计》是Java编程领域的一本经典教材,其第八版的源码资源包含例题、习题以及复习题的源代码,是学习和深入理解Java编程的重要辅助资料。这些源码由西安电子科技大学的李娜翻译,保证了内容的专业性和...

    Java并发程序设计教程

    4、线程间的协调手段:lock、condition、wait、notify、notifyAll☆☆☆ 5、Lock-free: atomic、concurrentMap.putIfAbsent、CopyOnWriteArrayList☆☆☆ 6、关于锁使用的经验介绍 7、并发流程控制手段:...

    java基础试题

    线程同步机制,如synchronized关键字、wait()、notify()和notifyAll()方法,以及Lock接口和Condition接口的使用,都是多线程编程中的重点。 6. **IO流**:Java的IO流分为字节流和字符流,以及输入流和输出流。了解...

    java工程师应聘基础知识

    线程同步是多线程编程中的关键,包括synchronized关键字、wait()、notify()和notifyAll()方法,以及Lock接口和Condition对象。此外,还有死锁、活锁和饥饿等并发问题需要理解和避免。 接下来是EJB(Enterprise ...

    Java编程并发程序设计

    4、线程间的协调手段:lock、condition、wait、notify、notifyAll☆☆☆ 5、Lock-free: atomic、concurrentMap.putIfAbsent、CopyOnWriteArrayList☆☆☆ 6、关于锁使用的经验介绍 7、并发流程控制手段:...

    Java JDK 7学习笔记(国内第一本Java 7,前期版本累计销量5万册)

    11.2.1 lock、readwritelock与condition 349 11.2.2 使用executor 357 11.2.3 并行collection简介 370 11.3 重点复习 373 11.4 课后练习 375 chapter12 通用api 377 12.1 日志 378 12.1.1 日志api简介...

    四川大学 2013和2014学年java试题

    Java编程语言是当今软件开发领域中的重要工具,尤其在...通过对这些知识点的复习和理解,考生可以更好地准备四川大学Java期末考试,提升自己的编程技能。同时,这些知识点也是Java程序员在实际工作中必须掌握的基础。

    阿里Java并发程序设计教程

    Java提供锁(lock)、条件(condition)、wait、notify和notifyAll等机制来实现线程间的通信。例如,synchronized关键字和ReentrantLock类可以用来创建互斥锁,condition对象可用于线程间的协调,而wait和notify/...

    阿里巴巴Java笔试面试题.zip_面试资料下载

    - Lock接口:熟悉ReentrantLock、Condition等锁机制,了解公平锁和非公平锁的概念。 - CountDownLatch、CyclicBarrier、Semaphore等同步工具类的应用。 4. **设计模式**: - 常见的设计模式如单例、工厂、观察者...

    java面试宝典与相关学习笔记

    - 掌握线程同步机制,如synchronized关键字、wait()、notify()和notifyAll()方法,以及Lock接口和Condition接口。 5. **内存管理与垃圾回收** - 理解Java内存模型,包括堆、栈、方法区、程序计数器等。 - 垃圾...

    Java开发程序设计教程

    Java提供了多种同步工具,如显式锁Lock、条件变量Condition、wait/notify/notifyAll机制等,用于线程间的通信和协作。 无锁编程(Lock-free)是一种实现并发程序设计的技术,它避免使用传统的锁机制,而是通过原子...

    2020年最新版-200+Java最常见的面试题汇总+答案总结汇总.pdf

    多线程是Java的一个强项,面试中可能会讨论线程同步机制,如synchronized关键字、volatile变量、Lock接口和Condition,以及死锁、活锁和饥饿等问题。 反射是Java的动态特性,允许在运行时检查类的信息并操作类的...

    阿里Java并发程序

    包括`Lock`、`Condition`、`wait()`、`notify()`和`notifyAll()`。`Lock`提供了比`synchronized`更细粒度的锁定控制,`Condition`允许在特定条件下释放锁。`wait()`、`notify()`和`notifyAll()`是基于对象监视器的...

Global site tag (gtag.js) - Google Analytics