进程、线程、纤程的区别

进程

通俗的说,进程就是一个程序运行起来的状态。一般情况下,一个程序运行起来之后,都会在操作系统中对应一个进程。

从操作系统的角度来说,进程是操作系统进行资源分配的基本单位。

线程

线程是CPU进行任务调度和执行的基本单位。

一个进程往往包含多个线程。

在Linux系统下是没有线程的概念的,它是用进程模拟的线程, 一般是某个主进程的子进程,因此把线程叫做轻量级进程。

线程的状态(Java)

NEW:  			新创建了一个线程对象,但还没有调用start()方法。 Thread t = new Thread();
RUNNABLE:  		Java线程中将就绪(ready)和运行中(running)两种状态笼统的成为“运行”   t.start()
BLOCKED :  	线程阻塞于锁, 只有synchronized才有这种状态,因为synchronized锁会经过CPU调度。
WAITING :  	等待  t.wait()
TIME_WAITING:  该状态不同于WAITING,它可以在指定的时间内自行返回 t.sleep(2000);
TERMINATED:		线程执行完毕

下面的代码表示了t1线程对应的不同状态:

Object o = new Object();
Thread t1 = new Thread(() -> { // NEW
    synchronized (o) { //BLOCKED
        try {
            Thread.sleep(2000); //TIME_WAITING
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
});// TERMINATED

Thread t2 = new Thread(() -> {
    try {
        t1.wait(); // WAITING
        t1.notify(); // RUNNABLE
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
});

t1.start(); // RUNNABLE  当没有抢夺到时间片时,为READY, 当被CPU调度执行时,状态为RUNNING
t2.start();
t2.join();

纤程

纤程又叫协程,可以看作是轻量级线程。

之所以称为轻量级线程,是因为它不需要由CPU来进行调度,与线程相比,纤程的切换损耗要小得多。

在一个线程内可以开启很多纤程,这些纤程只需要由当前线程来进行调度。

另一个角度来讲,它可以看作是用户态的线程。

纤程VS线程

目前Java的官方JDK中还没有支持创建纤程,对纤程的支持还在尝试阶段,为了实验纤程的效率,我们暂时先引入第三方lib对纤程的支持

场景:我们使用5W个线程来执行,每个线程中循环100次对count值加1,因为count 是AtomicInteger修饰的,所以是线程安全的。那么这5W个线程执行完后,count的值应为5000000。

使用线程的方式:

public class UseThread {
    static AtomicInteger count = new AtomicInteger(0);
    public static void main(String[] args) throws InterruptedException {
        Thread[] threads = new Thread[50000];
        long start = System.currentTimeMillis();
        for (int i = 0 ; i < threads.length; i++) {
            threads[i] = new Thread(() -> add());
            threads[i].start();
        }
        for (int i = 0 ; i < threads.length; i++) {
            threads[i].join();
        }
        System.out.println("count :" + count.get());
        System.out.println(System.currentTimeMillis() - start);
    }

    static void add()  {
        for (int i = 0; i < 100; i++) {
            count.getAndIncrement();
        }
    }
}

执行结果, 耗时:2370ms

在这里插入图片描述

接下来使用纤程的方式:

目前Java的官方JDK中还没有支持创建纤程,对纤程的支持还在尝试阶段,为了实验纤程的效率,我们暂时先引入第三方lib对纤程的支持

POM文件:

<dependency>
    <groupId>co.paralleluniverse</groupId>
    <artifactId>quasar-core</artifactId>
    <version>0.8.0</version>
</dependency>
public class UseFiber {
    static AtomicInteger count = new AtomicInteger(0);
    public static void main(String[] args) throws InterruptedException, ExecutionException {

        Fiber[] fibers = new Fiber[50000];
        long start = System.currentTimeMillis();
        for (int i = 0 ; i < fibers.length; i++) {
            fibers[i] = new Fiber(() ->add());
            fibers[i].start();
        }
        for (int i = 0 ; i < fibers.length; i++) {
            fibers[i].join();
        }
        System.out.println("count :" + count.get());
        System.out.println(System.currentTimeMillis() - start);
    }
    static void add() {

        for (int i = 0; i < 100; i++) {
            count.getAndIncrement();
        }

    }
}

执行结果, 耗时328ms
在这里插入图片描述
由此我们可以看到,在某些场景下,协程(纤程)的效率要高于线程。

协程的上下文切换是在用户空间,调度的成本相对较低。但是并不是协程一定比线程高效。

一般情况下,我们可以这样认为:

对于IO密集型的任务,协程更高效。(因为绝大部分时间都是在等待 IO)

对于CPU密集型的任务,线程更高效

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值