多个线程按顺序输出

来源:互联网 发布:cctv网络电视播放器 编辑:程序博客网 时间:2024/05/16 12:40

题目:编写一个程序,开启 3 个线程,这三个线程的 ID 分别为 A、B、C,每个线程将自己的 ID 在屏幕上打印 10 遍,要求输出的结果必须按顺序显示。如:ABCABCABC…… 

前4种统一使用一个全局变量state进行条件控制:

(1)state初始化为1,如果state为1执行A线程,A线程修改state为2执行B线程;如果state为2执行B线程,B线程修改state为3企图执行C线程;如果state为3执行C线程,C线程修改state为1,企图执行A线程。

(2)或者state初始化为0,如果state%3==0,执行A线程;如果state%3==1,执行B线程;如果stat%3==2,执行C线程。

解法1:采用volatile修饰的全局变量state作为条件控制,用for循环加if条件判断的忙等模式。

代码实现:

package com.yangliu.lock;import java.io.File;public class ABC1 {private static int n = 100000; //控制线程执行次数private volatile static int state = 0; //控制线程执行条件static class ThreadA extends Thread {public void run() {           for(int i=0;i<n;){           if(state%3==0){           System.out.println("A,loopNum="+i);           state++;           i++;           }           }}}static class ThreadB extends Thread {public void run() {for(int i=0;i<n;){           if(state%3==1){           System.out.println("B,loopNum="+i);           state++;           i++;           }           }}}static class ThreadC extends Thread {public void run() {for(int i=0;i<n;){           if(state%3==2){           System.out.println("C,loopNum="+i);           state++;           i++;           }           }}}public static void main(String[] args) throws InterruptedException {   long startTime = System.currentTimeMillis();   new ThreadA().start();   new ThreadB().start();   ThreadC c =new ThreadC();    c.start();    c.join();   long endTime = System.currentTimeMillis();   File f = new File("f.txt");   FileUtil.writeToFile(f, "n="+n);   FileUtil.writeToFile(f, "RunTime is "+(double)(endTime-startTime)/1000+"s");}}

问题:为什么共享变量要加volatile?加volatile就足够了吗?

分析:因为加volatile可以保证变量state的可见性,上一个线程对state的修改对下一个线程是可见的。另外由于有if条件做判断,所以可以确保只有单一的线程修改变量state的值,这里用volatile就足够了。

解法2:采用原子类AtomicInteger来控制变量state,其他不变

代码实现:

package com.yangliu.lock;import java.io.File;import java.util.concurrent.atomic.AtomicInteger;public class ABC2 {private static int n = 100000; //控制线程执行次数private static AtomicInteger state = new AtomicInteger(0); //控制线程执行条件static class ThreadA extends Thread {public void run() {           for(int i=0;i<n;){           if(state.get()%3==0){           System.out.println("A,loopNum="+i);           state.getAndIncrement();           i++;           }           }}}static class ThreadB extends Thread {public void run() {for(int i=0;i<n;){if(state.get()%3==1){           System.out.println("B,loopNum="+i);           state.getAndIncrement();           i++;           }           }}}static class ThreadC extends Thread {public void run() {for(int i=0;i<n;){if(state.get()%3==2){           System.out.println("C,loopNum="+i);           state.getAndIncrement();           i++;           }           }}}public static void main(String[] args) throws InterruptedException { long startTime = System.currentTimeMillis();   new ThreadA().start();   new ThreadB().start();   ThreadC c =new ThreadC();    c.start();    c.join();   long endTime = System.currentTimeMillis();   File f = new File("f.txt");   FileUtil.writeToFile(f, "RunTime is "+(double)(endTime-startTime)/1000+"s");}}

解法3:采用ReentrantLock锁住整段代码

代码实现:

package com.yangliu.lock;import java.io.File;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class ABC3 {private static int n = 100000; // 控制线程执行次数private static int state = 0; // 控制线程执行条件private static Lock lock = new ReentrantLock();static class ThreadA extends Thread {public void run() {for (int i = 0; i < n;) {lock.lock();if (state % 3 == 0) {System.out.println("A,loopNum=" + i);state++;i++;}lock.unlock();}}}static class ThreadB extends Thread {public void run() {for (int i = 0; i < n;) {lock.lock();if (state % 3 == 1) {System.out.println("B,loopNum=" + i);state++;i++;}lock.unlock();}}}static class ThreadC extends Thread {public void run() {for (int i = 0; i < n;) {lock.lock();if (state % 3 == 2) {System.out.println("C,loopNum=" + i);state++;i++;}lock.unlock();}}}public static void main(String[] args) throws InterruptedException { long startTime = System.currentTimeMillis(); new ThreadA().start(); new ThreadB().start(); ThreadC c =new ThreadC();    c.start();    c.join(); long endTime = System.currentTimeMillis(); File f = new File("f.txt"); FileUtil.writeToFile(f, "RunTime is "+(double)(endTime-startTime)/1000+"s");}}

解法4:采用ReentrantLock,三个Condition进行await和signal操作

代码实现:

package com.yangliu.lock;import java.io.File;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class ABC4 {private static int n = 100000; // 控制线程执行次数private static Lock lock = new ReentrantLock();private static Condition A = lock.newCondition();private static Condition B = lock.newCondition();private static Condition C = lock.newCondition();private static int state = 0;private static class ThreadA extends Thread {public void run() {lock.lock();try {for (int i = 0; i < n;i++) {if (state % 3 != 0)A.await();System.out.println("A,loopNum=" + i);state++;B.signal();}} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}}static class ThreadB extends Thread {public void run() {lock.lock();try {for (int i = 0; i < n;i++) {if (state % 3 != 1)B.await();System.out.println("B,loopNum=" + i);state++;C.signal();}} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}}static class ThreadC extends Thread {public void run() {lock.lock();try {for (int i = 0; i < n;i++) {if (state % 3 != 2)C.await();System.out.println("C,loopNum=" + i);state++;A.signal();}} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}}public static void main(String[] args) throws InterruptedException { long startTime = System.currentTimeMillis(); new ThreadA().start(); new ThreadB().start(); ThreadC c =new ThreadC();  c.start();  c.join(); long endTime = System.currentTimeMillis(); File f = new File("f.txt"); FileUtil.writeToFile(f, "RunTime is "+(double)(endTime-startTime)/1000+"s");}}

解法5:使用信号量机制,完全不用state变量进行条件控制

代码实现:

package com.yangliu.lock;import java.io.File;import java.util.concurrent.Semaphore;public class ABC5 {private static int n = 100000;    private static Semaphore AB = new Semaphore(0);    private static Semaphore BC = new Semaphore(0);    private static Semaphore CA = new Semaphore(0);        static class ThreadA extends Thread {        @Override        public void run() {            try {                for (int i = 0; i < n; i++) {                    CA.acquire();                    System.out.println("A,loopNum=" + i);                    AB.release();                }            } catch (InterruptedException e) {                e.printStackTrace();            }        }            }        static class ThreadB extends Thread {        @Override        public void run() {            try {                for (int i = 0; i < n; i++) {                    AB.acquire();                    System.out.println("B,loopNum=" + i);                    BC.release();                }            } catch (InterruptedException e) {                e.printStackTrace();            }        }            }        static class ThreadC extends Thread {        @Override        public void run() {            try {                for (int i = 0; i < n; i++) {                    BC.acquire();                    System.out.println("C,loopNum=" + i);                    CA.release();                }            } catch (InterruptedException e) {                e.printStackTrace();            }        }            }        public static void main(String[] args) throws InterruptedException {       long startTime = System.currentTimeMillis();       CA.release(); //释放CA,让A线程先执行    new ThreadA().start();    new ThreadB().start();    ThreadC c =new ThreadC();    c.start();    c.join();    long endTime = System.currentTimeMillis();    File f = new File("f.txt");   FileUtil.writeToFile(f, "RunTime is "+(double)(endTime-startTime)/1000+"s");       }}

当n取10万时的运行时间比较:

n=100000
RunTime is 5.623s
RunTime is 5.322s
RunTime is 4.482s
RunTime is 4.279s
RunTime is 3.842s

结果可知,第5种信号量机制运行时间最少,最佳。






阅读全文
2 0