死磕JAVA系列之 多线程引言

JAVA多线程是JAVA基础中一个比较难懂的部分,在并发编程中常用到的一个知识体系,在贪吃蛇小游戏的设计中也涉及到了多线程的知识, 计划写一点关于多线程的文章。 多线程的核心问题: 线程是什么?线程和进程的比较,如何创建一个线程?一个线程有什么状态,有那些属性?当多个线程同时运行时,如何设计线程的优先级,如何设计线程池呢? 故而这个系列的文章打算分三篇,来解决以上问题,(一)死磕Java系列之多线程创建和线程状态 ,主要涉及什么是线程,线程和进程的比较,如何创建一个线程,以及线程的状态;(二)死磕Java系列之多线程属性和线程同步 ,主要涉及线程的优先级和线程锁相关的知识;(三)死磕Java系列之线程池,主要涉及线程池相关的知识。
在这里插入图片描述
多线程程序和单线程程序的比较:

1. 单线程程序
单线程程序执行顺序是从前向后,按处理流程来执行语句,首先执行这一条----其次执行下一条-------接下来执行下一条…程序的执行顺序是一条长线,这条长线始终都会是一条。无论是调用方法,还是执行for 循环、if 条件分支语句,甚至更复杂的处理,都不会对这条长线产生影响。对于这种处理流程始终如一条线的程序,我们称之为单线程程序(single threaded program)。
  在单线程程序中,“在某一时间点执行的处理”只有一个。如果有人问起“程序的哪部分正在执行”,我们能够指着程序中的某一处回答说“这里,就是这儿”。这是因为,在单线程程序中,“正在执行程序的主体”只有一个。
比如说:

public class Main {
    public static void main(String[] args) {

      for (int i = 0; i < 1000; i++) {

        System.out.print("Good!");

      }

    }

  }

程序的执行顺序是:
在这里插入图片描述
main函数作为jvm虚拟机程序的入口,javac 命令便会编译源文件Main.java,并生成类文件Main.class。接下来,java 命令便会执行该程序,在屏幕上显示10 000 个Good!
在执行这个程序的时候至少有一个线程在执行,主线程会执行命令行中输入的类的main 方法。main 方法中的所有处理都执行完后,主线程也就终止了,
  上述代码中只有一个线程在运行,所以这是一个单线程程序。
2. 多线程程序
 由多个线程组成的程序就称为多线程程序。
 多个线程运行时,如果跟踪各个线程的运行轨迹,会发现其轨迹就像多条线交织在一起。
  假设有人问起“程序的哪部分正在执行”,而我们需要指出程序位置,并回答“这里,就是这儿”。那么在多线程的情况下,一根手指根本不够用,这时需要和线程个数一样多的手指。也就是说,如果有两个线程在运行,那就需要指出两个地方并回答“第一个线程正在这里执行,第二个线程在那里执行”;如果有三个线程,就要指出三个地方;如果有一百个线程,就要指出一百个地方。
  当规模大到一定程度时,应用程序中便会自然而然地出现某种形式的多线程。以下便是几种常见示例。

◆◆GUI 应用程序

几乎所有的GUI 应用程序中都存在多线程处理。例如,假设用户在使用文本工具编辑较大的文本文件时执行了文字查找操作。那么当文本工具在执行查找时,屏幕上会出现“停止查找”按钮,用户可随时停止查找。此时就需要用到多线程。

(1)执行查找

(2)显示按钮,并在按钮被按下时停止查找

这两个操作是分别交给不同的线程来执行的。这样一来,(1)的操作线程专门执行查找,而(2)的操作线程则专门执行GUI 操作,因此程序就会比较简单。

◆◆耗时的I/O 处理

一般来说,文件与网络的I/O 处理都非常消耗时间。如果在I/O 处理期间,程序基本上无法执行其他处理,那么性能将会下降。在这种情况下,就可以使用多线程来解决。如果将执行I/O 处理的线程和执行其他处理的线程分开,那么在I/O 处理期间,其他处理也可以同时执行。

◆◆多个客户端

基本上,网络服务器都需要同时处理多个客户端。但是,如果让服务器端针对多个客户端执行处理,那么程序会变得异常复杂。这种情况下,在客户端连接到服务器时,我们会为该客户端准备一个线程。这样一来,服务器程序就被设计成了好像只处理一个客户端。
  
多线程程序实例:

 
class Thread2 implements Runnable{  
    private String name;    
    public Thread2(String name) {  
        this.name=name;  
    }  

    @Override  
    public void run() {  
          for (int i = 0; i < 5; i++) {  
                System.out.println(name + "运行  :  " + i);  
                try {  
                    Thread.sleep((int) Math.random() * 10);  
                } catch (InterruptedException e) {  
                    e.printStackTrace();  
                }  
            }  
          
    }        
}  
public class Main {  
  
    public static void main(String[] args) {  
        new Thread(new Thread2("C")).start();  
        new Thread(new Thread2("D")).start();  
    }  
  
}  

运行结果:

输出:
C运行 : 0
D运行 : 0
D运行 : 1
C运行 : 1
D运行 : 2
C运行 : 2
D运行 : 3
C运行 : 3
D运行 : 4
C运行 : 4

Thread2类通过实现Runnable接口,使得该类有了多线程类的特征。run()方法是多线程程序的一个约定。所有的多线程代码都在run方法里面。Thread类实际上也是实现了Runnable接口的类。
main函数作为jvm虚拟机程序的入口,javac 命令便会编译源文件Main.java,并生成类文件Main.class。接下来,java 命令便会执行该程序,在启动的多线程的时候,需要先通过Thread类的构造方法Thread(Runnable target) 构造出对象,然后调用Thread对象的start()方法来运行多线程代码,多线程的执行是对于时间片的争夺,在没有设置线程优先级的时候,每个线程会争夺时间片来运行程序,故而结果是C D的混合输出。

猜你喜欢

转载自blog.csdn.net/weixin_41792162/article/details/85838088