0
点赞
收藏
分享

微信扫一扫

进程与线程

最后的执着 2022-01-31 阅读 78

1. 什么是进程?什么是程序?有什么区别?

程序:数据与指令的集合,程序是静态的 进程:给程序加入了时间的概念,不同的时间进程有不同的状态 进程是动态的,就代表OS中正在运行的程序 独立性,动态性,并发性

2. 什么是并行?什么是串行?什么是并发?

CPU:电脑的核心处理器,类似于“大脑” 串行:是指同一时刻一个CPU只能处理一件事,类似于单车道 并行:相对来说资源比较充足,多个CPU可以同时处理不同的多件事,类似于多车道 并发:相对来说资源比较紧缺,多个进程同时抢占公共资源,比如多个进程抢占一个CPU

3. 什么是线程?线程与进程有什么关系?

线程是OS能够进行运算调度的最小单位 一个进程可以拥有多个线程,当然,也可以只拥有一个线程,只有一个线程的进程被称作单线程程序 注意:每个线程也有自己独立的内存空间,当然也有一部分公共的空间用于保存共享的数据

在宏观上,一个CPU看似可以同时处理多件事 在微观上,一个CPU同一时刻只能处理一件事 结论:线程的执行具有随机性,我们控制不了,是由OS底层的算法来决定的

4.线程有几种状态?它们是怎么转换的?

  1. 新建状态:new–申请PCB,进行资源的分配

  2. 就绪/可运行状态:万事俱备只欠CPU,其实是将创建好的线程对象加入到就绪队列中,等待OS选中,这个选择我们是控制不了的

  3. 执行/运行状态:就绪队列中的线程被OS选中了,正在执行 注意:只有就绪状态才能切换成执行状态

  4. 阻塞状态:线程在执行中遇到了问题: 锁阻塞、休眠阻塞、等待阻塞…问题解决后再加入到就绪队列中

  5. 终止状态:线程成功执行完毕,释放资源 

     

    package cn.tedu.thread;
    /*本类用于实现多线程编程方案1:继承Thread类的方式*/
    public class TestThread {
        public static void main(String[] args) {
            Thread t1 = new MyThread();/*对应的是线程的新建状态*/
            Thread t2 = new MyThread();
            Thread t3 = new MyThread();
            Thread t4 = new MyThread();
    //        /*5.1测试1:自己主动调用run(),并没有多线程的效果*/
    //        t1.run();
    //        t2.run();
    //        t3.run();
    //        t4.run();
    
            t1.start();/*对应的是线程的就绪状态*/
            t2.start();
            t3.start();
            t4.start();
        }
    }
    //1.自定义线程类,并且让这个类继承Thread类
    class MyThread extends  Thread{
        //3.在run()完成自己的业务
        //业务需求:打印10次当前正在干活的业务
        @Override
        public void run() {
            for (int i = 0; i <10; i++) {
                System.out.println(i+getName());
            }
        }
    }
    package cn.tedu.thread;
    
    /*本类用于多线程编程实现方案二:实现Runnable接口*/
    public class TestRunnable {
        public static void main(String[] args) {
            //4.创建自定义线程类对象
            MyRunnable t = new MyRunnable();
            //5.创建线程对象,并将业务对象交给线程对象
            Thread t1 = new Thread(t);
            Thread t2 = new Thread(t);
            Thread t3 = new Thread(t);
            Thread t4 = new Thread(t);
            //6.以多线程的方式启动线程
            t1.start();
            t2.start();
            t3.start();
            t4.start();
        }
    }
    
    //1.自定义多线程类
    class MyRunnable implements Runnable {
        //2.添加父接口中未实现的抽象方法,这个方法用来完成自己的业务
        @Override
        public void run() {
            //3.完成业务:打印10次当前正在干活的线程名
            for (int i = 0; i < 10; i++) {
                /*问题:自定义类与与父接口Runable中都没有获取名字的方法
                 * 所以还需要从Thread类里找
                 * currentThread():静态方法,获取当前正在执行的线程对象
                 * getName():获取当前正在执行的线程对象的名称*/
                System.out.println(Thread.currentThread().getName() + i);
            }
        }
    }

     

    同步:体现了排队的效果,同一时刻只能有一个线程独占资源,其他没有权利的线程排队。 坏处就是效率会降低,不过保证了安全。 异步:体现了多线程抢占资源的效果,线程间互相不等待,互相抢占资源。 坏处就是有安全隐患,效率要高一些。

    synchronized同步关键字

     写法

    package cn.tedu.tickets;
    
    /*本类用于改造多线程售票案例,解决数据安全问题*/
    public class TestRunnableV2 {
        public static void main(String[] args) {
            //5.创建目标业务类对象
            TicketR2 target = new TicketR2();
            //6.创建线程对象
            Thread t1 = new Thread(target);
            Thread t2 = new Thread(target);
            Thread t3 = new Thread(target);
            Thread t4 = new Thread(target);
            //7.以多线程的方式运行
            t1.start();
            t2.start();
            t3.start();
            t4.start();
        }
    }
    
    /*1.多线程中出现数据安全问题的原因:多线程程序+共享数据+多条语句操作共享数据*/
    /*2.同步锁:相当于给容易出现问题的代码加了一把锁,包裹了所有可能会出现数据安全问题的代码
     * 加锁之后,就有了同步(排队)的效果,但是加锁的话,需要考虑:
     * 锁的范围:不能太大,太大,干啥都得排队,也不能太小,太小,锁不住,还是会有安全隐患*/
    //1.创建自定义多线程类
    class TicketR2 implements Runnable {
        //3.定义成员变量,保存票数
        int tickets = 100;
        //创建锁对象
        Object o = new Object();
    
        //2.实现接口中未实现的方法,run()中放着的是我们的业务
        @Override
        public void run() {
            //4.通过循环结构完成业务
            while (true) {
                /*3.同步代码块:synchronized(锁对象){会出现安全隐患的所有代码}
                 * 同步代码块在同一时刻,同一资源只会被一个线程独享*/
                /*这种写法不对,相当于每个线程进来的时候都会new一个锁对象,线程间使用的并不是同一把锁*/
                //synchronized (new Object()){
                //修改同步代码块的锁对象为成员变量o,因为锁对象必须唯一
                synchronized (o) {//同步代码块解决的是重卖的问题
                    //如果票数>0就卖票
                    if (tickets > 0) {
                        try {
                            Thread.sleep(10);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        //4.1打印当前正在售票的线程名以及票数-1
                        System.out.println(Thread.currentThread().getName() + "=" + tickets--);
                    }
                    //4.2退出死循环--没票的时候就结束
                    if (tickets <= 0) break;
                }
            }
        }
    }

     

    package cn.tedu.tickets;
    
    /*本类用于改造多线程售票案例,解决数据安全问题*/
    public class TestThreadV2 {
        public static void main(String[] args) {
            //5.创建多个线程对象并以多线程的方式运行
            TickectT2 t1 = new TickectT2();
            TickectT2 t2 = new TickectT2();
            TickectT2 t3 = new TickectT2();
            TickectT2 t4 = new TickectT2();
            t1.start();
            t2.start();
            t3.start();
            t4.start();
        }
    }
    
    //1.自定义多线程类
    class TickectT2 extends Thread {
        //3.新增成员变量用来保存票数
        static int tickets = 100;
        //static Object o = new Object();
    
        //2.添加重写的run()来完成业务
        @Override
        public void run() {
            //3.创建循环结构用来卖票
            while (true) {
                //Ctrl+Alt+L调整代码缩进
                //7.添加同步代码块,解决数据安全问题
                //synchronized (new Object()) {
                /*static的Object的对象o这种写法也可以*/
                //synchronized (o) {
                /*我们每通过class关键字创建一个类,就会在工作空间中生成一个唯一对应的类名.class字节码文件
                * 这个类名.class对应的对象我们称之为这个类的字节码对象
                * 字节码对象极其重要,是反射技术的基石,字节码对象中包含了当前类所有的关键信息
                * 所以,用这样一个唯一且明确的对象作为同步代码块的锁对象,再合适不过了*/
                synchronized (TickectT2.class) {/*比较标准的写法*/
                    if(tickets > 0){
                        //6.添加线程休眠,暴露问题
                        try {
                            Thread.sleep(10);//让线程休眠,增加线程状态切换的频率
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        //4.1打印当前正在售票的线程名与票数-1
                        System.out.println(getName() + "=" + tickets--);
                    }
                    //4.2给程序设置一个出口,没有票的时候就停止卖票
                    if (tickets <= 0) break;
                }
            }
        }
    }

举报

相关推荐

【进程与线程】

【多线程】进程与线程

(一)进程与线程

进程与线程(四)

谈谈进程与线程

0 条评论