• 走近并发编程之一 进程和线程


    并发与并行,进程与线程不仅是操作系统中及其重要的概念,也是并发编程入门

    必须要理解的核心知识。

    1. 什么是并发?并发与并行的区别

    顺序编程:程序中的所有事物在任意时刻都只能执行一个步骤

    并发:在同一时间段内,需要处理多个任务,而在每个时间点又只能处理一个,这就是并发。

    假设我们要把多个任务分配给处理机,如果这台机器有多个处理器,显然可以同时执行这些任务,这就是并行

    不同于并行,并发的目的旨在最大限度的提高程序在单处理器上的效率。前者是在物理上的同时发生,而并发是在逻辑上的同时发生。如图,如果要在同一个时间段内处理task1, task2,需要在任务之间来回切换,完成并发执行

    图:一个简单并发的例子

     

        2.  Java的多线程和并发性

    Java是一种多线程语言,并发是Java非常重要的高级特性之一。对于分布式系统甚至于web系统的开发者来说,学会高效的并发编程至关重要。例如,web系统是Java的常见应用之一,最基本的java web库类 Servlet就具备天生的多线程特性,图形用户界面类似于Swing和SWT也具备线程安全的机制。如果你不了解并发,你很难很好的使用好这些工具。

     

        3.  进程和线程

    进程可以定义为一个执行中的程序的实例,进程拥有自己的地址空间,以及用来记录进程的进程控制块(PCB)。想到实现并发,人们最先想到的便是通过进程。在多任务操作系统中,CPU会周期性地从一个进程切换到另一个进程。这种实现方式非常理想化,由于不同进程处于不同的地址空间,彼此之间不会干涉,这使得实现起来更为容易。

    可惜的是,虽然具有以上优点,但由于进程通常都会有开销和数量的限制,想要使用进程来并发编程显然不够经济。

    图:进程的开销( 任务管理器)

     

    函数型语言可以将并发任务彼此隔离,这种专门的并发语言为处理大量并发任务提供了方便。

    线程是在单一进程中创建的任务,线程与线程之间共享进程的地址空间和内存资源,Java的并发就是在顺序语言的基础上引入线程机制,通过多线程 之间的协作来实现并发。

    多线程并发的好处是可以共享资源,开销较小,然而同时也使得系统的复杂性增加。不过与程序设计的方便性,资源的负载均衡实现相比,复杂性代价也变得微不足道了。

     

        4.  线程的创建

    Java中创建线程,经常用到java.lang.Thread类,如下创建一个线程:

    Thread thread  = new Thread();

    调用start()方法启动线程

    thread.start();

    由于我们没有继承Thread类,重载Thread的run()方法,所以在start()之后线程没有任何动作。

    要想让线程执行我们想要它完成的任务,还需要创建Thread的子类来重载run()方法。

     

        5.  创建Thread子类

    举个栗子

    public class MyThread extends Thread {
    
        public void run(){
    
            System.out.println("ACFLOOD!");
    
        }
    
    }

    通过如下代码来运行MyThread

    MyThread myThread = new MyThread();
    
    myThread.start();

     

        6.  实现Runnable接口

    我们还可以通过实现Runnable接口来实现run()方法,你可能会问,Runnable和Thread的区别是什么? 其实,在Java的多线程机制中,Runnable的实现就相当于一个Task,也就是我们想让线程完成的任务。Thread的目的是用来驱动这些任务,我们想要执行Task,只需要把Runnable的实例放入Thread中。比如下面的倒计时任务LiftOff

    public class LiftOff implements Runnable {
    
      protected int countDown = 10; //Default
    
      private static int taskCount = 0;
    
      private final int id = taskCount++;
    
     
    
      public LiftOff(){}
    
      public LiftOff(int countDown){
    
          this.countDown = countDown;
    
      }
    
     
    
      public String status() {
    
          return "#" + id  + "(" + (countDown > 0 ? countDown : "LiftOff!")+").";
    
      }
    
     
    
      public void run(){
    
          while(countDown-- > 0){
    
            System.out.print(status());
    
            Thread.yield(); //对线程调度的建议
    
        }
    
      }
    
    }

     

    我们可以直接调用run()方法来执行。此时程序依旧是顺序执行,即只有主线程在运行,并没有新的线程被创建。

    public class MainThread {
    
        public static void main(String[] args){
    
            LiftOff launch = new LiftOff();
    
            laucn.run();
    
        }
    
    }

    更好的办法是交给Thread类来调度

    public class BasicThreads{
    
         Thread t = new Thread(new LiftOff());
    
         t.start();
    
         System.out.println("Waiting for LiftOff");       
    
    }

    在这个例子中,start()方法执行之后返回,之后输出main()主线程中的waiting for liftoff,run()在另一个线程最后执行完成。

     

        7.  总结

    通过本文的学习,相信读者对并发的基本概念,并发基本的实现原理,以及java多线程对于线程的创建有了初步的了解。在本系列的后续部分将会继续探讨并发编程中的细节。

     

    如果觉得本文对您有所帮助的话,就给俺点个赞吧~

     

  • 相关阅读:
    Linux入门学习(二)
    Linux入门学习(一)
    正则表达式(二)
    正则表达式入门
    我的第一个博客
    Java每日问题汇总-04
    Java每日问题汇总-03
    Java每日问题汇总-02
    #{ }和${ }参数值的获取的区别
    Cause: org.apache.ibatis.binding.BindingException: Parameter 'eName' not found.解决方案
  • 原文地址:https://www.cnblogs.com/ACFLOOD/p/5544224.html
Copyright © 2020-2023  润新知