• 多线程


    多线程(上)

    基本概念:程序、进程、线程

    • 程序(program)是为了完成特定任务、用某种语言编写地一组指令的集合。即指一段静态的代码,静态对象。
    • 进程(process)是程序的依次执行过程,或是正在运行的一个程序。是一个动态的工程:有它自身的产生、存在和消亡的过程。-----生命周期
      • 程序是静态的,进程是动态的
      • 进程作为资源分配的单位,系统在运行时会为每个进程分配不同的内存区域
    • 线程(thread),进程可进一步细化为线程,是一个程序内部的一条执行路径。
      • 若一个进程同一时间并行执行多个线程,就是支持多线程的
      • 线程作为调度和执行的单位,每个线程拥有独立的运行栈和程序计数器(pc),线程切换的开销小
      • 一个进程中的多个线程共享相同的内存单元/内存地址空间->它们从同一堆中分配对象,可以访问相同的遍历狼和对象。这就使得线程间通信更简便、高效。但多个线程操作共享的系统资源可能就会带来安全隐患。
    • 一个Java应用程序java.exe,其实至少有三个线程:main()主线程,gc()垃圾回收线程,异常处理线程。如果发生异常,会影响主线程。
    • 并行与并发
      • 并行:多个CPU同时执行多个任务。比如:多个人同时做不同的事。
      • 并发:一个CPU(采用时间片)同时执行多个任务。比如:秒杀、多个人做同一件事。
        image
        image
    • 多线程的创建,方式一:继承于Thread类
      1. 创建一个继承于Thread类的子类
      2. 重写Thread类的run()-->将此线程执行的操作声明在run()中
      3. 创建Thread类的子类的对象
      4. 通过此对象调用start()
    //例:遍历100以内的所有的偶数
    //1.创建一个继承于Thread类的子类
    class Mythread extends Thread{
        //2.重写Thread类的run()
        @Override
        public void run() {
            for (int i = 0; i < 100; i++) {
                if (i%2==0){
                    System.out.println(Thread.currentThread().getName()+":"+i);
                }
    
            }
        }
    }
    public class ThreadTest {
        public static void main(String[] args) {
            //3.创建Thread类的子类的对象
            Mythread t1 = new Mythread();
            //4.通过此对象调用start():4.1启动当前线程 4.2调用当前线程的run()
            //问题一:我们不能通过直接调用run()的方式启动线程
    //        t1.run();
            t1.start();
            //问题二:再启动一个线程遍历100内的偶数,错误,不可以还让已经start()的线程去执行。会报IllegalThreadStateException异常
            //我们需要重新创建一个线程的对象
    //        t1.start();
            Mythread t2 = new Mythread();
            t2.start();
    //创建Thread匿名子类的方式
            new Thread(){
                @Override
                public void run() {
                    for (int i = 0; i < 100; i++) {
                        System.out.println("匿名子类方式");
                    }
                }
            }.start();
            //如下操作在main方法中执行
            for (int i = 0; i < 100; i++) {
                if (i%2!=0){
                    System.out.println(Thread.currentThread().getName()+":"+i);
                }
    
            }
        }
    }
    
    • Thread中常用方法:

      1. start():启动当前线程;调用当前线程的run()
      2. run():通常需要重写Thread类中的此方法,将创建的线程要执行的操作声明在此方法中
      3. currentThread():静态方法,返回执行当前代码的线程
      4. getName():获取当前线程的名字
      5. setName():设置当前线程的名字
      6. yield():释放当前cpu的执行权
      7. join():在线程a中调用线程b的join(),此时线程啊就进入阻塞状态,直到线程b完全执行完以后,线程a才结束阻塞状态
      8. stop():已过时,当执行完此方法时,强制结束当前线程
      9. sleep(long millitime):让当前线程“睡眠”指定的millitime毫秒。在指定的millitime毫秒时间内,当前线程时阻塞状态。
      10. isAlive():判断当前线程是否还存活
    • 线程的调度

      1. 调度策略
        • 时间片
        • 抢占式:高优先级的线程抢占CPU
      2. Java的调度方法
        • 同优先级线程组成先进先出队列(先到先服务),使用时间片策略
        • 对高优先级,使用有限调度的抢占式策略
      3. 线程的优先级等级
        • MAX_PRIORITY:10
        • MIN_PRIORITY:1
        • NORM_PRIORITY:5
        • 涉及的方法:
          • getPriority():返回线程优先值
          • setPriority(int newPriority):改变线程的优先级
        • 说明:
          • 线程创建时继承父线程的优先级
          • 低优先级只是获得调度的概率低,并非一定是在高优先级线程之后才被调用
          • 高优先级的线程要抢占低优先级线程cpu的执行权。但是只是从概率上讲,高优先级的线程高概率的抢矿下被执行。并不意味着只有当高优先级的线程执行完以后,低优先级的线程才执行。
    • 创建多线程的方式二:实现Runnable接口

      1. 创建一个实现了Runnable接口的类
      2. 实现类去实现Runnable中的抽象方法:run()
      3. 创建实现类的对象
      4. 将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
      5. 通过Thread类的对象调用start()
    /*
    * 创建多线程的方式二:实现Runnable接口
    	1. 创建一个实现了Runnable接口的类
    	2. 实现类去实现Runnable中的抽象方法:run()
    	3. 创建实现类的对象
    	4. 将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
    	5. 通过Thread类的对象调用start()
     */
    //1.创建一个实现了Runnable接口的类
    class MThread implements Runnable{
        //实现类去实现Runnable中的抽象方法:run()
        @Override
        public void run() {
            for (int i = 0; i < 100; i++) {
                if(i % 2 == 0){
                    System.out.println(Thread.currentThread().getName()+":"+i);
                }
            }
        }
    }
    public class ThreadTest1 {
        public static void main(String[] args) {
            //3.创建实现类的对象
            MThread mThread = new MThread();
            //4.将此对象传入到Thread类的构造中,创建Thread的对象
            Thread thread = new Thread(mThread);
            //5.通过Thread类的对象调用start 5.1 启动线程 5.2 调用当前线程的run--->调用了Runnable类型的target的run方法
            thread.setName("线程一");
            thread.start();
    
            //再启动一个线程,遍历100以内的偶数
            Thread t2 = new Thread(mThread);
            t2.setName("线程二");
            t2.start();
        }
    }
    
    • 比较创建线程的两种方式:
      • 开发中:优先选择:实现Runnable接口的方式
      • 原因:1.实现的方式没有类的单继承性的局限性 2.实现的方式更适合来处理多个线程有共享数据的情况
      • 联系:public class Thread implements Runnable
      • 相同点:两种方式都需要重写run(),将线程要执行的逻辑声明在run()中。

    image
    image

  • 相关阅读:
    STM32F107的DAC配置
    步进电机工作原理
    winform笔记本蓝牙与外部蓝牙设备通信
    C#里三种强制类型转换
    IE6/7BUG之OL有序列表没顺序
    IE6/7BUG之列表UL楼梯
    IE6/7BUG之A超链接无效
    IE6/7BUG之overflow:hidden无效
    linux shell 管道命令(pipe)使用及与shell重定向区别
    UGUI研究院之全面理解图集与使用
  • 原文地址:https://www.cnblogs.com/rhy2103/p/16271000.html
Copyright © 2020-2023  润新知