Java:学习什么是多线程

线程是什么

进程是对CPU的抽象,而线程更细化了进程的运行流程

先看一下这个图

Java:学习什么是多线程

线程和进程的关系有

  1. 进程中就是线程在执行,所有(主)线程执行完了进程也就结束了
  2. 多个线程从1秒钟是同时运行完成,从1纳秒(或是更小的单位)看是排队执行
  3. 在不断运行的进程中(没有IO操作),使用多个线程并没有提高进程的执行效率,还有所降低

 

为什么需要多线程

我第一次使用线程是在学习BIO和多线程进行通信时
服务端每次接收到一个客户端的请求就创建一个线程(虽然可以使用tomcat和Netty大大优化了BIO,但它们也使用了多线程)

就这个用法而言,难道不能用多进程代替多线程进行通信吗(不知道提出这个问题是不是太笨了)

我的理解是:

  1. 多个客户端和服务端通信时,服务端有很多资源是多个客户端共用的
  2. 如果使用多进程,也就是运行很多个服务端,相同服务端就得存放相同的资源在电脑内存中,太浪费空间了(如果是为了防止故障存在多台机器肯定就不浪费)
  3. 所以创建了线程这个概念去共用进程的资源

 

线程需要什么

  业务场景还是在通信中

  • 服务端线程需要在客户端发消息过来时及时响应,至于怎么响应肯定就写在自己的代码逻辑里
    • 所以线程需要一段可以执行的代码块
  • A发消息,就得切换到与A通信的线程,B发消息,就得切换到与B通信的线程,线程就得不停的切换
    • 所以CPU得知道哪个线程和A通信等,就得给线程个ID好辨认


总之线程还需要各种各样我没学过的东西。

 

下面根据自己的理解,实现一个简单的用户线程

用户线程:如果里面有一个线程执行不下去了(等待输入、运行报错、死循环),操作系统并不认识用户线程,只认识用户进程,会让整个用户进程执行不下去

 

实现一个简单的用户线程

线程的数据结构

MyThread.java

 

 1 import java.lang.reflect.Constructor;
 2 import java.lang.reflect.InvocationTargetException;
 3 import java.lang.reflect.Method;
 4 
 5 public class MyThread<T> {
 6 
 7     private int Id;//区分各个线程的标识符
 8     private int runTime;//线程当前可以运行的时间片
 9     private int totalTime; //线程总共需要运行的时间
10     private int priority;//线程的优先级
11     //交给线程执行的代码块,用一个对象参数替代
12     public T data;
13 
14     public MyThread() {
15     }
16 
17     public MyThread(int id, int totalTime,int priority, T data) {
18 
19         this.Id = id;
20 //        this.runTime = runTime;
21         this.totalTime = totalTime;
22         this.runTime = totalTime/2;//固定线程每次运行时间片是总时间的二分之一,方便测试
23         this.priority = priority;
24         this.data = data;
25     }
26 
27     public void run(){
28 
29         try {
30 
31             System.out.println("线程id:"+Id);
32             System.out.println("剩余时间片:" + runTime);
33             System.out.println("线程优先级:"+priority);
34 
35             //使用java的反射机制,执行代码块的内容
36             Class<?> clazz = data.getClass();
37             Constructor constructor = clazz.getDeclaredConstructor();
38             Object object = constructor.newInstance();
39 
40             Method method = clazz.getMethod("hello");
41             method.invoke(object);
42 
43             //每执行一次,线程总时间减少
44             //运行的时间片不变
45             totalTime-=runTime;
46 //            判断线程运行总时间是否快要结束了
47             runTime = Math.min(totalTime,runTime);
48 
49         } catch (NoSuchMethodException e) {
50             e.printStackTrace();
51         } catch (InvocationTargetException e) {
52             e.printStackTrace();
53         } catch (InstantiationException e) {
54             e.printStackTrace();
55         } catch (IllegalAccessException e) {
56             e.printStackTrace();
57         }
58 
59     }
60 
61     public int getPriority() {
62         return priority;
63     }
64 
65     public int getRunTime() {
66         return runTime;
67     }
68 
69     public int getTotalTime() {
70         return totalTime;
71     }
72 }

 

 

写一个类代替代码块供线程执行

 1 public class MyMethod {
 2 
 3     public MyMethod() {
 4 
 5     }
 6 
 7     public void hello(){
 8         System.out.println("hello");
 9     }
10 
11 }

 

测试线程的执行

 1 import java.util.Comparator;
 2 import java.util.PriorityQueue;
 3 public class Test {
 4 
 5     public static void main(String[] args) {
 6 
 7         //由优先队列进行线程的调度,即优先级高的线程先执行,优先级相同采用先入先出算法
 8         PriorityQueue<MyThread> priorityQueue = new PriorityQueue<>(new Comparator<MyThread>() {
 9             @Override
10             public int compare(MyThread o1, MyThread o2) {
11                 return o2.getPriority() - o1.getPriority();
12             }
13         });
14 
15         MyMethod method = new MyMethod();
16         //创建三个线程
17         MyThread<MyMethod> myThread = new MyThread<>(1,3,5,method);
18         MyThread<MyMethod> myThread1 = new MyThread<>(2,3,5,method);
19         MyThread<MyMethod> myThread2 = new MyThread<>(3,2,10,method);
20         //线程进入队列
21         priorityQueue.offer(myThread);
22         priorityQueue.offer(myThread1);
23         priorityQueue.offer(myThread2);
24 
25         //在循环中不断的执行线程
26 
27         while (!priorityQueue.isEmpty()){
28 
29             MyThread<MyMethod> myThreadRun = priorityQueue.poll();
30 
31             myThreadRun.run();
32 
33             //线程总时间不为0,进入队列等待下次执行
34             if (myThreadRun.getTotalTime() != 0){
35                 priorityQueue.offer(myThreadRun);
36             }
37         }
38 
39         System.out.println("线程都执行完了,进程也就结束了");
40     }
41 }

执行结果

Java:学习什么是多线程

 

 

总结

  1. 这个用户线程的例子实现的不好
  2. 例子中总共有四个线程,主线程担任了一个调度线程的职责
  3. 在操作系统中,线程的执行
    • 操作系统会不断主动去询问线程的时间片结束没,一旦结束就将线程换下
  4. 多线程排队执行出现竞争
    • 一个线程执行一个打印命令,对应了CPU中的多条指令
    • 如果指令没执行完,切换到了其他线程,再换回来执行指令,就会出现一种竞争的情况
上一篇:dgl._ffi.base.DGLError: [10:36:44] /opt/dgl/src/runtime/c_runtime_api.cc:88: Check failed: allow_mis


下一篇:从"runtime类型模块是否可以依赖runtime类型模块?"看UnrealBuildTool的基本概念及流程