经典线程同步问题

 

生产者消费者问题

读者作家问题

哲学家吃饭问题

 

 

生产者消费者问题

 
分别用锁、信号量、同步监视器模拟的例子。
package thread;

import java.util.Random;
import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class Item {
    int id;

    public Item(int id) {
        this.id = id;
    }

    public String toString() {
        return "[item " + id + "]";
    }
}

abstract class Buffer {
    int capacity;
    Item[] items;
    int count;
    int in, out;

    public Buffer(int capacity) {
        this.capacity = capacity;
        items = new Item[capacity];
        count = 0;
        in = out = 0;
    }

    abstract void put(Item item);

    abstract Item get();

    public void printBuf() {
        System.out.print("current buf status: [ ");
        for (int i = 0; i < capacity; i++) {
            System.out.print(items[i] + " ");
        }
        System.out.print("] ");
        System.out.print("count:" + count + " ");
        System.out.print("in:" + in + " out:" + out + " ");
        System.out.println();
    }
}

/**
 * 利用锁实现线程同步的buffer
 * 
 * @author jd
 * 
 */
class LockBuffer extends Buffer {

    Lock lock = new ReentrantLock();
    Condition empty = lock.newCondition();
    Condition full = lock.newCondition();

    public LockBuffer(int capacity) {
        super(capacity);
    }

    public void put(Item item) {
        lock.lock();

        try {
            while (count == capacity)
                full.await();
            items[in] = item;
            in = (in + 1) % capacity;
            count++;
            empty.signal();

            System.out.println(Thread.currentThread().getName() + " put item " + item.id);
            printBuf();

        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        finally {
            lock.unlock();
        }
    }

    public Item get() {
        lock.lock();
        Item res = null;
        try {
            while (count == 0)
                empty.await();
            res = items[out];
            items[out] = null;
            out = (out + 1) % capacity;
            count--;
            full.signal();

            System.out.println(Thread.currentThread().getName() + " get item " + res.id);
            printBuf();

        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
        return res;
    }

}

/**
 * 利用信号量实现的线程同步的buffer
 * 
 * @author jd
 * 
 */
class SemaphoreBuffer extends Buffer {
    Semaphore mutex;
    Semaphore full;
    Semaphore empty;

    public SemaphoreBuffer(int capacity) {
        super(capacity);
        mutex = new Semaphore(1);
        full = new Semaphore(0);
        empty = new Semaphore(capacity);
    }

    public void put(Item item) {

        try {
            empty.acquire();
            mutex.acquire();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        items[in] = item;
        in = (in + 1) % capacity;
        count++;

        System.out.println(Thread.currentThread().getName() + " put item " + item.id);
        printBuf();

        mutex.release();
        full.release();

    }

    public Item get() {

        try {
            full.acquire();
            mutex.acquire();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        Item res = items[out];
        items[out] = null;
        out = (out + 1) % capacity;
        count--;

        System.out.println(Thread.currentThread().getName() + " get item " + res.id);
        printBuf();

        mutex.release();
        empty.release();
        return res;
    }

}

/**
 * 利用同步监视器实现的线程同步的buffer
 * 
 * @author jd
 * 
 */
class MonitorBuffer extends Buffer {

    public MonitorBuffer(int capacity) {
        super(capacity);
    }

    public void put(Item item) {
        synchronized (this) {

            try {
                while (count == capacity)
                    wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            items[in] = item;
            in = (in + 1) % capacity;
            count++;
            notifyAll();

            System.out.println(Thread.currentThread().getName() + " put item " + item.id);
            printBuf();

        }
    }

    public Item get() {
        synchronized (this) {
            try {
                while (count == 0)
                    wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            Item res = items[out];
            items[out] = null;
            out = (out + 1) % capacity;
            count--;
            notifyAll();

            System.out.println(Thread.currentThread().getName() + " get item " + res.id);
            printBuf();
            return res;
        }
    }
}

class Producer implements Runnable {
    Buffer buf;
    Random rand = new Random();

    public Producer(Buffer buf) {
        this.buf = buf;
    }

    public void run() {
        for (int i = 0; i < 10; i++) {
            Item item = new Item(rand.nextInt(100));
            buf.put(item);

            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }
}

class Consumer implements Runnable {
    Buffer buf;

    public Consumer(Buffer buf) {
        this.buf = buf;
    }

    public void run() {
        for (int i = 0; i < 10; i++) {
            Item item = buf.get();

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public class BoundedBufferTest {

    public static void main(String[] args) {
        // Buffer buf = new LockBuffer(5);
        // Buffer buf = new SemaphoreBuffer(5);
        Buffer buf = new MonitorBuffer(5);

        // 3个生产者,3个消费者,每个生产或者消费10次。
        for (int i = 0; i < 3; i++) {
            new Thread(new Producer(buf), "p" + i).start();
            new Thread(new Consumer(buf), "c" + i).start();
        }

    }
}
View Code

 

 

读者作家问题

 
模拟第一读者问题。
package thread;

import java.util.concurrent.Semaphore;

/**
 * first reader writer problem, writer may starve;
 * 
 * @author jd
 * 
 */
class Article {
    String content = "The original content.";
    Semaphore mutex, wrt;
    int readCount;

    public Article() {
        mutex = new Semaphore(1);
        wrt = new Semaphore(1);
        readCount = 0;
    }

    public String read() throws InterruptedException {
        mutex.acquire();
        readCount++;
        if (readCount == 1)
            wrt.acquire();
        mutex.release();

        // reading is performed
        String res = content;
        System.out.println(Thread.currentThread().getName() + " is reading, the article is [" + res + "]");
        Thread.sleep(1000);

        mutex.acquire();
        readCount--;
        if (readCount == 0)
            wrt.release();
        mutex.release();

        return res;

    }

    public void Write(String str) throws InterruptedException {
        wrt.acquire();

        // writing is performed
        content = "new content(" + str + ")";
        System.out.println("content is changed to [" + content + "]");
        Thread.sleep(2000);

        wrt.release();
    }

}

class Reader implements Runnable {
    Article art;

    public Reader(Article a) {
        art = a;
    }

    public void run() {
        try {
            art.read();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class Writer implements Runnable {
    Article art;

    public Writer(Article a) {
        art = a;
    }

    public void run() {
        try {
            art.Write(Thread.currentThread().getName());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

public class ReaderWriterTest {

    public static void main(String[] args) {
        Article art = new Article();

        for (int i = 0; i < 3; i++) {
            new Thread(new Reader(art), "r" + i).start();
        }
        // writer starves;
        new Thread(new Writer(art), "w").start();

        for (int i = 0; i < 3; i++) {
            new Thread(new Reader(art), "rr" + i).start();
        }

    }
}
View Code

 

哲学家吃饭问题

http://en.wikipedia.org/wiki/Dining_philosophers_problem

 

模拟哲学家吃饭问题,该实现可能会产生死锁。

package thread;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * This version may lead to deadlock.
 * 
 * @author jd
 * 
 */
class Chopstick {
    private Lock lock = new ReentrantLock();

    public void pickUp() {
        lock.lock();
    }

    public void putDown() {
        lock.unlock();
    }

}

class Philosopher extends Thread {
    private Chopstick left;
    private Chopstick right;

    public Philosopher(Chopstick left, Chopstick right) {
        this.left = left;
        this.right = right;
    }

    public void eat() {
        pickUp();
        // eating
        System.out.println(Thread.currentThread().getName() + " is eating");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        putDown();
        System.out.println(Thread.currentThread().getName() + " done eating");

    }

    public void pickUp() {
        System.out.println(Thread.currentThread().getName() + " is trying to pick up left chopstick..");
        left.pickUp();

        // this sleep makes all philosopers pick up left chopstick and try to
        // pick up the right, which leads to a deadlock.
        // this rarely happens, but it can do.
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(Thread.currentThread().getName() + " is trying to pick up right chopstick..");
        right.pickUp();
    }

    public void putDown() {
        left.putDown();
        right.putDown();
    }

    public void run() {
        eat();
    }
}

public class DiningPhilosopherTest {

    public static void main(String[] args) {
        Chopstick[] chopsticks = new Chopstick[5];
        for (int i = 0; i < 5; i++)
            chopsticks[i] = new Chopstick();

        for (int i = 0; i < 5; i++) {
            new Philosopher(chopsticks[i], chopsticks[(i + 1) % 5]).start();
        }

    }
}
View Code

 

不死锁版本,当某个哲学家无法拿到两只筷子时,会主动放弃已有资源(筷子)而放弃本次吃饭。

package thread;

import java.util.Random;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 
 * @author jd
 * 
 */
class ChopstickNoDeadLock {
    private Lock lock = new ReentrantLock();

    public boolean pickUp() {
        return lock.tryLock();
    }

    public void putDown() {
        lock.unlock();
    }

}

class PhilosopherNoDeadLock extends Thread {
    Random rand = new Random();
    private ChopstickNoDeadLock left;
    private ChopstickNoDeadLock right;

    public PhilosopherNoDeadLock(ChopstickNoDeadLock left, ChopstickNoDeadLock right) {
        this.left = left;
        this.right = right;
    }

    public void eat() {
        if (pickUp()) {
            pickUp();
            // eating
            System.out.println(Thread.currentThread().getName() + " is eating");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            putDown();
            System.out.println(Thread.currentThread().getName() + " done eating");
        } else {
            System.out.println(Thread.currentThread().getName() + " gives up eating");

        }
    }

    public boolean pickUp() {
        System.out.println(Thread.currentThread().getName() + " is trying to pick up left chopstick..");
        if (!left.pickUp()) {
            return false;
        }

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(Thread.currentThread().getName() + " is trying to pick up right chopstick..");
        if (!right.pickUp()) {
            left.putDown();
            return false;
        }

        return true;
    }

    public void putDown() {
        left.putDown();
        right.putDown();
    }

    public void run() {
        // for (int i = 0; i < 10; i++) {
        eat();
        // try {
        // Thread.sleep(rand.nextInt(10) * 100);
        // } catch (InterruptedException e) {
        // e.printStackTrace();
        // }
        // }
    }
}

public class DiningPhilosopherTestNoDeadLock {

    public static void main(String[] args) {
        ChopstickNoDeadLock[] chopsticks = new ChopstickNoDeadLock[5];
        for (int i = 0; i < 5; i++)
            chopsticks[i] = new ChopstickNoDeadLock();

        for (int i = 0; i < 5; i++) {
            new PhilosopherNoDeadLock(chopsticks[i], chopsticks[(i + 1) % 5]).start();
        }

    }
}
View Code

 

posted @ 2014-09-15 22:12  jdflyfly  阅读(311)  评论(1编辑  收藏  举报