进程与线程

进程与线程

1.进程

1.1独立性,动态性,并发性

进程就是正在运行的程序,它代表了程序所占用的内存区域,一个进程具有独立的内存空间,是一个正在系统中活动的指令集合,程序加入了时间的概念以后,称为进程,具有自己的生命周期和各种不同的状态,多个进程可以在单个处理器CPU上并发执行,之间不会互相影响。

1.2并行与并发

并行:多个CPU同时处理不同的进程
高并发:一个CPU处理多个进程,抢占资源
在高并发的情景中,尽可能的保证程序的可用性,减少系统不能提供服务的时间

2.线程

2.1线程与进程的关系

线程是操作系统OS能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。一个操作系统中可以有多个进程,一个进程中可以包含一个线程(单线程程序),也可以包含多个线程(多线程程序)。每个线程在共享同一个进程中的内存的同时,又有自己独立的内存空间。
在这里插入图片描述

2.2多线程

随机性:线程的随机性指的是同一时刻,只有一个程序在执行。

CPU分时调度:时间片,即CPU分配给各个线程的一个时间段,称作它的时间片,即该线程被允许运行的时间,如果在时间片用完时线程还在执行,那CPU将被剥夺并分配给另一个线程,将当前线程挂起,如果线程在时间片用完之前阻塞或结束,则CPU当即进行切换,从而避免CPU资源浪费,当再次切换到之前挂起的线程,恢复现场,继续执行。

注意:我们无法控制OS选择执行哪些线程,OS底层有自己规则,如:

  • FCFS(First Come First Service 先来先服务算法)
  • SJS(Short Job Service短服务算法)

2.3线程的状态

  • 就绪(可运行)状态:线程已经准备好运行,只要获得CPU,就可立即执行
  • 执行(运行)状态:线程已经获得CPU,其程序正在运行的状态
  • 阻塞状态:正在运行的线程由于某些事件(I/O请求等)暂时无法执行的状态,即线程执行阻塞
    在这里插入图片描述
  • 创建状态:线程的创建比较复杂,需要先申请PCB,然后为该线程运行分配必须的资源,并将该线程转为就绪状态插入到就绪队列中
  • 终止状态:等待OS进行善后处理,最后将PCB清零,并将PCB返回给系统
    在这里插入图片描述

在这里插入图片描述

3.多线程代码创建方式1:继承Thread

public class TestThread1 {
    public static void main(String[] args) {
        MyThread t = new MyThread();/*new对应线程的新建状态*/
        /*如果只是通过两个线程对象调用run(),那么会先执行完一个线程的任务
        * 再执行另外一个线程的任务*/
        //t.run();
        MyThread t2 = new MyThread();
        //t2.run();
        /*start()对应的状态是线程的就绪状态,什么时候执行,取决于什么时候被OS选中*/
        /*当调用start()启动线程时,底层虚拟机会自动调用run()执行我们的业务*/
        /*线程执行的效果具有随机性,执行结果不可控
        * 具体取决于CPU的调度,时间片的分配*/
        t.start();
        t2.start();
        /*自定义线程名*/
        MyThread t3 = new MyThread("中国");
        t3.start();
    }
}

class MyThread extends Thread {

    public MyThread(String name) {
        super(name);
    }

    public MyThread() {

    }

    @Override
    public void run() {
        /*自定义线程类的业务需要写在重写的run()里
        * super.run()表示调用的是父类的业务*/
        //super.run();

        for (int i = 0; i < 10; i++) {
            /*getName()方法表示可以获取当前正在执行的线程名称*/
            System.out.println(i+"="+getName());
        }
    }
}

4.多线程代码创建方式2:实现Runnable接口

public interface Runnable {
    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}

Runnable接口中只有一个抽象方法run()
在这里插入图片描述

public Thread(Runnable target) {
        init(null, target, "Thread-" + nextThreadNum(), 0);
    }

Thread的构造方法传入Runnable的实现类对象,不直接实例化Thread类的原因是可以对一个对象实现多个线程同时调用。

public class TestThread2 {
    public static void main(String[] args) {
        /*目标业务对象,只需要创建一次,类似于系统给所有玩家发布了同一个任务target*/
        MyRunnable target = new MyRunnable();
        //模拟多线程,创建多个线程对象
        /*Runnable与MyRunnable都没有start()
        * 需要将接口实现类创建的目标业务对象target与多线程类Thread建立关系*/
        Thread t1 = new Thread(target);
        Thread t2 = new Thread(target);
        Thread t3 = new Thread(target);
        Thread t4 = new Thread(target);
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}

/*多线程实现方法二:implements Runnable*/
class MyRunnable implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            /*Runnable接口中,没有提供多余的方法,唯独只有一个抽象的run()
            * Thread.currentThread() 获取当前正在执行的线程对象
            * Thread是java.lang包下的,可以直接使用
            * Thread.currentThread() 是静态方法,所以可以通过类名直接调用
            * getName() 获取当前线程对象的名字*/
            System.out.println(i+"="+Thread.currentThread().getName());
        }

    }
}

售票实例(无同步锁)

public class TestThread {
    public static void main(String[] args) {
        TicketThread t1 = new TicketThread();
        TicketThread t2 = new TicketThread();
        TicketThread t3 = new TicketThread();
        TicketThread t4 = new TicketThread();
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}

class TicketThread extends Thread {
    /*ticket成员变量被所有对象共享,每个对象都会调用100张票*/
    //int tickets = 100;//票数

    /*静态资源属于类资源,被全局所有对象共享*/
    static int tickets = 100;

    @Override
    public void run() {
        while (true) {
            try {
                /*本方法是让线程休眠的方法,参数为毫秒,此处休眠10ms*/
                /*如果线程在休眠后仍然没有问题,才说明线程不会出现问题*/
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(getName()+"="+tickets--);
            if (tickets <= 0) {
                break;
            }
        }
    }
}
public class TestRunnable {
    public static void main(String[] args) {
        TicketRunnable target = new TicketRunnable();
        Thread t1 = new Thread(target,"霄");
        Thread t2 = new Thread(target);
        Thread t3 = new Thread(target);
        Thread t4 = new Thread(target);
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}
 class TicketRunnable implements Runnable {
    /*ticket不需要设置静态,此类只实例化一次*/
     int tickets = 100;
     @Override
     public void run() {

         while (true) {
             try {
                 Thread.sleep(10);
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }
             System.out.println(Thread.currentThread().getName()+"="+tickets--);
             if (tickets <= 0) {
                 break;
             }
         }

     }
 }

这两种方法都存在同一张票重复售出,多售(票数为负)原因在于没有同步锁,多个线程被赋予时间片时,对同一张票进行操作。
比如:对线程一给予2.5个时间片(假设一张票一个时间片),线程一在销售第三张票时被阻塞,导致第三张票没有卖出,而后OS给予线程二2.5个时间片把第三张票卖出,等到了再次给予线程一时间片,第三张票又被卖出。(仅己愚见)
常见情况是由于线程的随机性+访问延迟。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在C语言中,进程线程是并发编程中重要的概念。进程(Process)是操作系统分配资源的基本单位,它具有独立的地址空间和系统资源,可以独立运行。而线程(Thread)则是进程的一个执行单元,是进程内部的一个分支,与同一进程中的其他线程共享地址空间和系统资源。 进程线程的区别主要体现在以下几个方面: 1. 资源开销:进程的资源开销较大,每个进程都有独立的内存空间、文件描述符等系统资源。而线程进程共享同一进程的资源,因此线程的资源开销较小。 2. 并发性:进程是独立运行的实体,进程间通过进程间通信(IPC)进行数据交换。而线程是在同一进程内并发执行的,它们共享进程的数据和资源,因此线程的并发性较高。 3. 调度和切换:进程切换涉及到上下文切换,需要保存和恢复进程的执行状态,开销较大。而线程的切换只涉及到线程的调度,开销较小。 4. 同步与通信:进程之间的通信和同步需要通过IPC机制,如管道、消息队列、信号量等。而线程之间可以通过共享内存和互斥量等方式进行同步和通信,开销较小。 总之,进程线程在资源开销、并发性、调度和切换、同步与通信等方面有着不同的特点和适用场景。在C语言中,通过使用多线程技术可以实现并发编程,提高程序的效率和性能。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [C++多线程----进程线程区别](https://blog.csdn.net/weixin_43956732/article/details/109736126)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值