您好,登錄后才能下訂單哦!
首先打印1-100數字如果用一個單線程實現那么只要一個for循環即可,那么如果要用兩個線程打印出來呢?(一個線程打印奇數,一個線程打印偶數)于是大家會想到可以通過加鎖實現,但是這樣的效率是不是不高?這里我用一個變量來控制兩個線程的輸出
public class ThreadTest { volatile int flag=0; public void runThread() throws InterruptedException{ Thread t1=new Thread(new Thread1()); Thread t2=new Thread(new Thread2()); t1.start(); t2.start(); } public class Thread1 implements Runnable{ public void run() { int i=0; while(i<=99){ if(flag==0) { System.out.println("t1="+i+"flag="+flag); i+=2; flag=1; } } } } public class Thread2 implements Runnable{ public void run() { int i=1; while(i<=99){ if(flag==1) { System.out.println("t2="+i+"flag="+flag); i+=2; flag=0; } } } } }
那么如果要實現三個線程輪流打印1-100的數字呢?是不是也可以用上面的方法實現呢?代碼如下
public class ThreadTest { private int i=0; private Thread thread1,thread2,thread3; private int flag=0; public void runThread() throws InterruptedException{ thread1=new Thread(new Thread1()); thread2=new Thread(new Thread2()); thread3=new Thread(new Thread3()); thread1.start(); thread2.start(); thread3.start(); } public class Thread1 implements Runnable{ public void run() { while(i<=100){ if(flag==0) { System.out.println("t1="+i); i++; flag=1; } } } } public class Thread2 implements Runnable{ public void run() { while(i<=100){ if(flag==1) { System.out.println("t2="+i); i++; flag=2; } } } } public class Thread3 implements Runnable{ public void run() { while(i<=100){ if(flag==2) { System.out.println("t3="+i); i++; flag=0; } } } } }
運行結果
發現三個線程只打印了一次就停止不輸出了,是什么原因呢?
可以用jdk自帶的jstack來看看線程的狀態,在windows系統中可以打開cmd然后進入jdk所在目錄,然后執行Jsp,能查看到各線程id,然后執行jstack -F pid就可以看的狀態了
可以看到幾個Thread state是BLOCKED,就是阻塞了,什么原因呢?
尷尬發現flag變量和i變量前面忘記加volatile,導致flag和i被線程讀取修改時,其他線程不可見,所以才導致上面的問題出現。
在JVM中每個線程讀取變量到cache中時相互都是不可見的,也就是java五大內存區中的程序計數器區域對于每個線程都是獨立的不共享的,只有堆內存區和方法區是對所有線程都是共享的。
當線程1讀取了flag和i的值,并對其進行修改的時候,線程2并發運行,并不知道flag和i值已經改變,導致多線程數據不一致的情況,所以加了volatile后,當線程讀取變量進行修改后會“通知”其它線程這個值已經進行了修改。
import java.util.concurrent.atomic.AtomicInteger; public class ThreadTest { private volatile int i=0; private Thread thread1,thread2,thread3; private volatile int flag=0; public void runThread() throws InterruptedException{ thread1=new Thread(new Thread1()); thread2=new Thread(new Thread2()); thread3=new Thread(new Thread3()); thread1.start(); thread2.start(); thread3.start(); } public class Thread1 implements Runnable{ public void run() { while(i<100){ if(flag==0) { System.out.println("t1="+i); i++; flag=1; } } } } public class Thread2 implements Runnable{ public void run() { while(i<100){ if(flag==1){ System.out.println("t2="+i); i++; flag=2; } } } } public class Thread3 implements Runnable{ public void run() { while(i<100){ if(flag==2){ System.out.println("t3="+i); i++; flag=0; } } } } }
運行結果
-----未完-----
補充知識:Java n個線程輪流打印數字的問題
一、兩個線程輪流打印數字。
加鎖實現:
package lianxi; /* * 用鎖實現兩個線程輪流打印1——100 */ public class Print1TO100TwoThread { private Object lock = new Object(); private int i = 0; Thread threadA = new Thread(new Runnable() { @Override public void run() { while (i <= 100) { synchronized (lock) { try { if (i > 100) break; System.out.println("threadA :" + (i++)); lock.notify(); lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } }); Thread threadB = new Thread(new Runnable() { @Override public void run() { while (i <= 100) { synchronized (lock) { try { if (i > 100) break; System.out.println("threadB :" + (i++)); lock.notify(); lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } }); public void startTwoThread() throws InterruptedException { threadA.start(); Thread.sleep(20); threadB.start(); } public static void main(String[] args) throws InterruptedException { new Print1TO100TwoThread().startTwoThread(); } }
用鎖效率太低,用一個變量來控制打印的順序。
package lianxi; /* * 用兩個線程輪流打印1——10;用所實現效率太低,用變量來控制 */ public class PrinntNumTwoThread { private volatile int num = 0; private volatile boolean flag = false; Thread threadA = new Thread(new Runnable() { @Override public void run() { while (true) { if (num > 10) return; if (!flag) { System.out.println("threadA-->" + ":" + (num++)); flag = !flag; } } } }); Thread threadB = new Thread(new Runnable() { @Override public void run() { while (true) { if (num > 10) return; if (flag) { System.out.println("threadB-->" + ":" + (num++)); flag = !flag; } } } }); public void startTwoThread() { threadA.start(); threadB.start(); } public static void main(String[] args) { new PrinntNumTwoThread().startTwoThread(); } }
二、那么如果要實現三個線程輪流打印1-100的數字呢?
package lianxi; public class PrintNumThreeThread { private volatile int i = 0; private volatile int flag = 0; Thread threadA = new Thread(new Runnable() { @Override public void run() { while (true) { if (i > 100) return; if (flag == 0) { System.out.println("threadA->" + ":" + (i++)); flag = 1; } } } }); Thread threadB = new Thread(new Runnable() { @Override public void run() { while (true) { if (i > 100) return; if (flag == 1) { System.out.println("threadB->" + ":" + (i++)); flag = 2; } } } }); Thread threadC = new Thread(new Runnable() { @Override public void run() { while (true) { if (i > 100) return; if (flag == 2) { System.out.println("threadC->" + ":" + (i++)); flag = 0; } } } }); public void startThreeThread() { threadA.start(); threadB.start(); threadC.start(); } public static void main(String[] args) { new PrintNumThreeThread().startThreeThread(); } }
以上這篇Java實現多線程輪流打印1-100的數字操作就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持億速云。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。