背景说明:
在学了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+"次");
}
}