多线程-利用semaphore多线程顺序打印ABC

semaphore介绍

先说它的构造方法:

    //参数permits是许可的数量
    public Semaphore(int permits) {
        sync = new NonfairSync(permits);
    }

    //第二个参数是,是否是公平锁
    /**
     * Creates a {@code Semaphore} with the given number of
     * permits and the given fairness setting.
     *
     * @param permits the initial number of permits available.
     *        This value may be negative, in which case releases
     *        must occur before any acquires will be granted.
     * @param fair {@code true} if this semaphore will guarantee
    //fair为true的时候,semaphore保证在竞争permits的时候先进先出,先获得许可先执行
     *        first-in first-out granting of permits under contention,
     *        else {@code false}
     */
    public Semaphore(int permits, boolean fair) {
        sync = fair ? new FairSync(permits) : new NonfairSync(permits);
    }
公平信号量是指获得锁的顺序与线程启动的顺序有关,非公平信息量就是无关的了。
非公平信号量线程启动的顺序与调用semaphore.acquire()的顺序无关,也就是线程先启动了并不代表先获得许可。

公平与不公平通过Semaphore类的构造函数new Semaphore(int permits,boolean fair)的第二个参数fair决定。

再说说它的两个方法:

    /**
    //官方文档解释的很清楚,从semaphore(信号量)对象中获取一个许可,此semaphore许可permits数量会减1,如果当前许可的数量为0,
//线程会阻塞直到有可用的许可permit 或者线程被中断
     * Acquires a permit from this semaphore, blocking until one is
     * available, or the thread is {@linkplain Thread#interrupt interrupted}.
     *
     * 

Acquires a permit, if one is available and returns immediately, * reducing the number of available permits by one. * *

If no permit is available then the current thread becomes * disabled for thread scheduling purposes and lies dormant until * one of two things happens: *

        //此semaphore对象permits数量增加,需要其他线程调用此semaphore对象的release方法 *
  • Some other thread invokes the {@link #release} method for this * semaphore and the current thread is next to be assigned a permit; or *
  • Some other thread {@linkplain Thread#interrupt interrupts} * the current thread. *
* *

If the current thread: *

    *
  • has its interrupted status set on entry to this method; or *
  • is {@linkplain Thread#interrupt interrupted} while waiting * for a permit, *
* then {@link InterruptedException} is thrown and the current thread's * interrupted status is cleared. * * @throws InterruptedException if the current thread is interrupted */ public void acquire() throws InterruptedException { sync.acquireSharedInterruptibly(1); }
    /**
     * Releases a permit, returning it to the semaphore.
     *
    //释放一个许可,是permits的数量加1,
     * 

Releases a permit, increasing the number of available permits by * one. If any threads are trying to acquire a permit, then one is * selected and given the permit that was just released. That thread * is (re)enabled for thread scheduling purposes. * *

There is no requirement that a thread that releases a permit must * have acquired that permit by calling {@link #acquire}. * Correct usage of a semaphore is established by programming convention * in the application. */ public void release() { sync.releaseShared(1); }

顺序打印ABC思路

定义三个线程“ThreadA”、“ThreadB”、“ThreadC”它们的run()方法分别打印"A",“B”,“C”,我们定义三个信号量对象来控制线程ABC的执行顺序,初始化A信号量semaphore的permits的数量为1,线程ThreadA 执行run前调用信号量A对象的acquire()方法,所以A线程可以执行。初始化B、C信号量的permits数量为0,在线程ThreadB、ThreadC执行前分别调用B、C信号量的acquire()方法,由于permits的数量为0,所有ThreadB、ThreadC线程会阻塞。打印完“A”字母之后,我们调用B信号量的release()方法,这样阻塞的ThreadB线程就能顺利执行了,以此类推完成“A”,“B”,“C”的顺序打印。

import java.util.concurrent.Semaphore;

public class ABC_Semaphore {
    // 以A开始的信号量,初始信号量数量为1
    private static Semaphore A = new Semaphore(1,true);
    // B、C信号量,A完成后开始,初始信号数量为0
    private static Semaphore B = new Semaphore(0);
    private static Semaphore C = new Semaphore(0);

    static class ThreadA extends Thread {

        @Override
        public void run() {
            try {
                for (int i = 0; i < 10; i++) {
                    A.acquire();// A获取信号执行
                    System.out.println("A");
                    B.release();// B释放信号,B信号量为1,可以执行
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    static class ThreadB extends Thread {

        @Override
        public void run() {
            try {
                for (int i = 0; i < 10; i++) {
                    B.acquire();
                    System.out.println("B");
                    C.release();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    static class ThreadC extends Thread {

        @Override
        public void run() {
            try {
                for (int i = 0; i < 10; i++) {
                    C.acquire();
                    System.out.println("C");
                    System.out.println("---------------------");
                    A.release();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        //顺序打印abc
        new ThreadA().start();
        new ThreadB().start();
        new ThreadC().start();
    }


你可能感兴趣的:(多线程)