背景說明:
在學了Java的多線程(繼承Thread,Runnable)以后,我出於好奇,就想知道java到底是不是多線程的,不能它說自己是多線程就是多線程,自己想驗證一下,於是我就想測試一下,但繼承Thread由於java的單繼承形式,導致不能生成多線程,但是Runnable可以,於是我就做了一個腳本(個人感覺一個java文件就是一個腳本,沒有上升到項目級別),我同時生成了10個線程,來模擬購票系統,假設一個線程模擬一個人去購10張票,一個人購買一張票的時間是0.5s(不可同時去購買兩張票及以上),然后觀察這100張票用多少時間購買完成。
所遇到的問題1:
問題描述:
首先就是計算一共用了多少時間了,我利用了如下圖的代碼框架來編寫,發現一個問題:因為當前java主程序也是一個線程,當主java程序在運行時,在創建完這10個線程后,主Java程序就執行完成了,它不會管這10個線程是否運行完成,在時間計算時,出現了問題。總時間會在線程運行時輸出(輸出的時間不是線程運行的時間)
解決步驟1:
解決方案如圖,解釋一下:我在接口實現類中定義了一個線程靜態共享變量,這個時候,當10個線程創建成功並運行,在最后一個線程運行完畢是對endTIme進行最后一次修改,該endTime就是這十個線程最后運行完成的時間,再進行時間計算。問題也就來了,還是沒有解決時間的統計,因為java主程序還是一個線程,時間輸出錯誤。
解決步驟2:
考慮到java主程序也是一個線程,我在創建10個線程后,立即休眠java 主線程(提前預估時間並設置相應的休眠時間),休眠時間稍微比線程運算預估時間大一點
最后:
時間問題解決,但是這個時候引發了一個大的問題,當10個線程在訪問同一個數據並修改時,數據可能發生異常。這個時候就需要線程對數據的互斥機制。
代碼:
主程序java代碼:javaThreadTest
package org.axc.com.javathread;
import java.util.Scanner;
/**
*
* @ClassName: javaThreadTest
* @Description: 測試java線程的運行
* @author Anxc
* @date 2019年8月8日
*
*/
public class JavaThreadTest {
public static void main(String[] args) {
// 線程的創建
MyThread mythread;
System.out.println("---------繼承Thread方式來實現創建線程-----------------");
Scanner in = new Scanner(System.in);
String menu="線程測試開始";
int chioce=1;
while(chioce!=0) {
mythread = new MyThread();
System.out.println("請輸入非0來開始調試繼承的Thread");
System.out.print(">>");
chioce = in.nextInt();
if(chioce==0) {
System.out.println("ByeBye");
break;
}
// 輸出菜單
System.out.println(menu);
// 線程運行
mythread.start();
}
System.out.println("------------利用Runnable接口實現創建線程-------------");
// 測試Runnable的多線程所用時間
chioce = 1;
// 利用Runnable接口,初始化線程
Runnable runnable = new MyRunnable();
long startTime;
long endTime;
while(chioce!=0) {
System.out.println("請輸入非0來開始調試");
System.out.print(">>");
chioce = in.nextInt();
if(chioce == 0) {
System.out.println("Runnable ByeBye!");
break;
}
startTime = System.currentTimeMillis();
System.out.println(startTime);
// 創建10個線程來觀察是否是真的多線程運行
new Thread(runnable).start();
new Thread(runnable).start();
new Thread(runnable).start();
new Thread(runnable).start();
new Thread(runnable).start();
new Thread(runnable).start();
new Thread(runnable).start();
new Thread(runnable).start();
new Thread(runnable).start();
new Thread(runnable).start();
Thread t=new Thread(runnable);
//t.isAlive();//判斷線程是否存活
try {
Thread.sleep(8000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 輸出最后所用時間
System.out.println("最終所用時間為:"+(((MyRunnable) runnable).getEndTime()-startTime));
}
}
}
實現接口Runnable的java程序代碼:MyRunnable
package org.axc.com.javathread;
/**
*
* @ClassName: MyRunnable
* @Description: 測試Runnable的真正多線程
* @author Anxc
* @date 2019年8月8日
*
*/
public class MyRunnable implements Runnable {
private static int count=100; //加互斥鎖,當一個線程去修改值時,其它線程不能讀取
public static long endTime;
private static boolean flag=true;
public MyRunnable() {
}
@Override
public void run() {
int num=10;
// 加鎖,使修改變量時只有一個線程在操作
while(num>0) {
if(flag) {
flag=false;//加鎖
count--;
// TODO Auto-generated method stub
System.out.println("當前剩余"+count);
flag=true;//關鎖
}
else {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
continue;
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
num--;
}
// 獲取線程運行終止時間
endTime = System.currentTimeMillis();
// System.out.println(endTime);
}
public long getEndTime() {
return endTime;
}
}
繼承Thread的方法的java程序:MyThread
package org.axc.com.javathread;
/**
*
* @ClassName: MyThread
* @Description: java線程的實現方式之一繼承Thread
* @author Anxc
* @date 2019年8月8日
*
*/
public class MyThread extends Thread {
private static int count = 0;
public void run() {
int num=0;
count++;
while(num<5) {
System.out.println("再等等!"+count+num);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
num++;
}
System.out.println("當前已經累計運行該線程:"+count+"次");
}
}