• 进程和线程


     什么是进程?

    • 进程是操作系统中运行的一个任务(一个应用程序运行在一个进程中)
    • 进程(process)是一块包含了某些资源的内存区域,操作系统利用进程把它的工作划分为一些功能单元。
    • 进程包含一个或多个线程。进程还拥有一个私有的虚拟地址空间,该空间仅能被它所包含的线程访问。
    • 线程只能归属于一个进程并且它只能访问该进程所拥有的资源,当操作系统创建一个进程后,该进程会自动申请一个主线程或者首要线程的线程。

    什么是线程

    • 一个线程是进程的一个顺序执行流
    • 同类的多个线程共享一块内存空间和一组系统资源,线程本身有一个供程序执行时的堆栈,线程是切换负荷小,因此线程也被成为轻负荷经常。

    进程和线程的区别

    • 一个进程至少拥有一个线程
    • 进程拥有独立的内存单元,而多个线程共享内存。
    • 每个独立线程有一个程序运行的入口,顺序执行序列和程序的出口。
    • 线程不能独立执行

    为什么要用多线程?

    生活中的多线程:

    • 单车道容易拥堵,多车道,路况畅通。
    • 车间中一条生产线生产缓慢,增加多条生产线,同时生产出更多的产品。

    使用场合:

    • 程序中需要同时完成多个任务的情况,可以将每个任务定义为一个线程,使他们一同工作。
    • 有些单一线程可以完成,但是多线程可以更快,如下载文件等

    多线程的缺点:

    1. 如果有大量的线程,会影响性能,因为操作系统需要在它们之间切换.
    2. 更多的线程需要更多的内存空间
    3. 线程中止需要考虑对程序运行的影响.
    4. 通常块模型数据是在多个线程间共享的,需要防止线程死锁情况的发生

    并发原理

    多个线程“同时”运行只是我们感官上的一种表现。事实上线程是并发运行的(时间片轮转进程调度算法),单个CPU的情况下任何一个时间内有且仅有一个进程占有CPU,如果有多个CPU,情况就不同了,如果进程数小于CPU数,则不同的进程可以分配给不同的CPU来运行,这样,各个进程就是真正同时运行的,这便是并行。但如果进程数大于CPU数,则仍然需要使用并发技术。OS将时间划分为很多时间片段(时间片),尽可能的均匀分配给每一个线程,获取时间片段的线程被CPU运行,而其他线程全部等,只要每个时间片段足够小,用户根本感觉不出来CPU是在轮流为多个进程服务,就好象所有的进程都在不间断地运行一样。所有并发技术不是绝对意义上的“同时发生”。

    线程的状态

    线程是一个动态执行的过程,它也有一个从产生到死亡的过程。

    下图显示了一个线程完整的生命周期。

    1、新建状态(New):新创建了一个线程对象。
    2、就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权。
    3、运行状态(Running):就绪状态的线程获取了CPU,执行程序代码。
    4、阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:
    (一)、等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。(wait会释放持有的锁)
    (二)、同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。
    (三)、其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。(注意,sleep是不会释放持有的锁)
    5、死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

    多线程的创建

    Java 提供了三种创建线程的方法:

    1、使用thread创建并启动线程。

    public class testThread {
    
        public static void main(String[] args){
            Thread t1=new MyThread();
            Thread t2=new MyThread();
            t1.start();
            t2.start();
        }
    }
    
    /*运行TestThread类,控制台会输出两次0-4。*/
    class MyThread extends Thread{
        public void run(){
            for(int i=0;i<5;i++){
                System.out.println(i);
            } 
        }
    }

     2、实现Runnable接口

    public class testThread implements Runnable{
    
    	public void run(){
    		for(int i=0;i<5;i++){
    			System.out.println(i);
    		}	
    	}
    	public static void main(String[] args){
    		testThread t1=new testThread();
    		Thread t=new Thread(t1);
    		t.start();
    	}
    }
    

     3、内部类的方式实现

        public static void main(String[] args){
    
            Thread t=new Thread(){
                public void run(){
                    for(int i=0;i<5;i++){
                        System.out.println(i);
                    }    
                }
            };
            t.start();
        }

     总结:

    1、Thread类是线程类,每一个实例表示一个可以并发运行的线程。我们可以通过继承该类并重写run方法来定义一个具体的线程,run是定义该线程要执行的逻辑。启动线程是调用线程的start()方法。start()方法会将当前线程纳入线程调度,当线程获取时间片后会自动开始执行run方法中的逻辑。

    2、实现runnable的好处在于可以将线程与线程要执行的任务分类开减少耦合,同时java是单继承的,这样可以去实现其他父类或者接口。

    3、当一个线程仅需要一个实例是,推荐使用匿名内部类的方式创建线程,简化编写代码的复杂度。

  • 相关阅读:
    BZOJ1406: [AHOI2007]密码箱 数论
    BZOJ5188: [Usaco2018 Jan]MooTube 并查集+离线处理
    BZOJ2662: [BeiJing wc2012]冻结 spfa+分层图
    BZOJ1297: [SCOI2009]迷路 矩阵快速幂
    BZOJ4887: [Tjoi2017]可乐 矩阵快速幂
    BZOJ5168: [HAOI2014]贴海报 线段树
    开发富文本编辑器的一些经验教训
    数据可视化的发展前景、商业/职业前景?
    市场调研中如何做数据分析?
    当前火热的短视频,背后有着哪些黑科技技术?
  • 原文地址:https://www.cnblogs.com/magic101/p/7827969.html
Copyright © 2020-2023  润新知