The semaphore

This is the preferred method without controlling the order in which threads are started. Simple idea, directly on the code, if you need to increase the number of printing is also very convenient.


    static class PrintSemaphore implements Runnable {
        String printValue;

        Semaphore selfSemaphore;

        Semaphore nextSemaphore;

        public void setSelfSemaphore(Semaphore selfSemaphore) {
            this.selfSemaphore = selfSemaphore;
        }

        public void setNextSemaphore(Semaphore nextSemaphore) {
            this.nextSemaphore = nextSemaphore;
        }

        public PrintSemaphore(String printValue) {
            this.printValue = printValue;
        }

        @Override
        public void run(a) {
            while (true) {
                try {
                    selfSemaphore.acquire();// Get semaphore, s-1
                    System.out.println(printValue);
                    nextSemaphore.release();// Release semaphore, s + 1
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch blocke.printStackTrace(); }}}}public static void main(String[] args) {
        // The semaphore controls the number of threads allowed to access simultaneously
        Semaphore sA = new Semaphore(1);
        Semaphore sB = new Semaphore(0);
        Semaphore sC = new Semaphore(0);

        PrintSemaphore printSemaphoreA = new PrintSemaphore("A");
        PrintSemaphore printSemaphoreB = new PrintSemaphore("B");
        PrintSemaphore printSemaphoreC = new PrintSemaphore("C");

        printSemaphoreA.setSelfSemaphore(sA);
        printSemaphoreA.setNextSemaphore(sB);

        printSemaphoreB.setSelfSemaphore(sB);
        printSemaphoreB.setNextSemaphore(sC);

        printSemaphoreC.setSelfSemaphore(sC);
        printSemaphoreC.setNextSemaphore(sA);


        ExecutorService exe = Executors.newCachedThreadPool();
        exe.execute(printSemaphoreB);
        exe.execute(printSemaphoreC);
        exe.execute(printSemaphoreA);


    }
Copy the code

Using synchronized

Analysis of the

Looking at A sequence called CABC, we can see that CA, printing A, takes the lock of C in front of it (indicating that C has finished), as well as its own lock. AB, printing B requires taking the previous lock of A (indicating that A has finished), as well as its own lock. BC, printing A requires taking the previous lock of B (indicating that B is done), as well as its own lock. Just print the threads of ABC and start them in order, that is, A has finished executing once when B starts and B has finished executing once when C starts. So the order of the sequence is guaranteed.

simulation

Print A line first start, get C+A lock, release A lock after execution, and notifyAll. Then wait on the C lock. After an interval, the print B thread starts, it requests A lock and takes it, then gets its own B lock, prints B., releases the B lock, and notifyAll. Then wait at lock A. Note: at this time to print A thread wait C, print B threads wait A after the interval time, print C thread start, request B lock and get it, then get their C lock, print c., release the lock C, and notifyAll. Then wait on lock B. At this point, we find that the condition for printing thread A is met, and it can get the C lock and its own A lock. Print thread B wait A, print thread C wait B print ABC

class PrintThreadSyn implements Runnable {
    / / print the value
    String value;
    // The front lock
    Object preLock;

    public void setPreLock(Runnable runnable) {
        preLock = runnable;
    }

    public PrintThreadSyn(String value) {
        this.value = value;
    }

    @Override
    public void run(a) {

        synchronized (preLock) {
            while (true) {
                synchronized (this) {
                    System.out.println(value);
                    this.notifyAll();
                }
                try {
                    preLock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

public static void main(String[] args) throws InterruptedException {
        // ------------------------------synchronized--ABC-----------------------------
        // Loop to print ABC
        PrintThreadSyn threadA = new PrintThreadSyn("A");
        PrintThreadSyn threadB = new PrintThreadSyn("B");
        PrintThreadSyn threadC = new PrintThreadSyn("C");

        threadA.setPreLock(threadC);
        threadB.setPreLock(threadA);
        threadC.setPreLock(threadB);

        new Thread(threadA).start();
        Thread.sleep(500);
        new Thread(threadB).start();
        Thread.sleep(500);
        new Thread(threadC).start();
}
Copy the code

Printing AB simply simplifies the code, leaving the class unchanged

        // Circularly print AB
        PrintThreadSyn threadA = new PrintThreadSyn("A");
        PrintThreadSyn threadB = new PrintThreadSyn("B");

       threadA.setPreLock(threadB);
       threadB.setPreLock(threadA);
			 
       new Thread(threadA).start();
			 Thread.sleep(500);
       new Thread(threadB).start();
Copy the code

ReentrantLock

ReentrantLock+Condition instead of SYN +notify+wait

 class PrintThreadReentrantLock implements Runnable {
        String value;
        ReentrantLock lock;
        Condition preCondition;
        Condition selfCondition;

        public void setLock(ReentrantLock lock) {
            this.lock = lock;
        }

        public void setPreCondition(Condition condition) {
            this.preCondition = condition;
        }

        public void setSelfCondition(Condition condition) {
            this.selfCondition = condition;
        }

        public PrintThreadReentrantLock(String value) {
            this.value = value;
        }

        @Override
        public void run(a) {

            lock.lock();
            while (true) {

                System.out.println(value);
                selfCondition.signalAll();
                try {
                    preCondition.await();
                } catch(InterruptedException e) { e.printStackTrace(); }}//lock.unlock();}}public static void main(String[] args) throws InterruptedException {

		    PrintThreadReentrantLock threadA = new PrintThreadReentrantLock("A");
        PrintThreadReentrantLock threadB = new PrintThreadReentrantLock("B");
        PrintThreadReentrantLock threadC = new PrintThreadReentrantLock("C");

        ReentrantLock reentrantLock = new ReentrantLock();
        threadA.setLock(reentrantLock);
        threadB.setLock(reentrantLock);
        threadC.setLock(reentrantLock);


        Condition conditionA = reentrantLock.newCondition();
        Condition conditionB = reentrantLock.newCondition();
        Condition conditionC = reentrantLock.newCondition();
        threadA.setSelfCondition(conditionA);
        threadB.setSelfCondition(conditionB);
        threadC.setSelfCondition(conditionC);

        threadA.setPreCondition(conditionC);
        threadB.setPreCondition(conditionA);
        threadC.setPreCondition(conditionB);

        new Thread(threadA).start();
        Thread.sleep(500);
        new Thread(threadB).start();
        Thread.sleep(500);
        new Thread(threadC).start();
	}			
Copy the code

Printing AB simply simplifies the code, leaving the class unchanged

        PrintThreadReentrantLock threadA = new PrintThreadReentrantLock("A");
        PrintThreadReentrantLock threadB = new PrintThreadReentrantLock("B");

        ReentrantLock reentrantLock = new ReentrantLock();
        threadA.setLock(reentrantLock);
        threadB.setLock(reentrantLock);

        Condition conditionA = reentrantLock.newCondition();
        Condition conditionB = reentrantLock.newCondition();
        threadA.setSelfCondition(conditionA);
        threadB.setSelfCondition(conditionB);

        threadA.setPreCondition(conditionB);
        threadB.setPreCondition(conditionA);

        new Thread(threadA).start();
        Thread.sleep(500);
        new Thread(threadB).start();
Copy the code