zoukankan      html  css  js  c++  java
  • Java基础总结--多线程总结1

    ----进程和线程-----
    1.概述:简单理解一个进程就是一个正在运行的程序(程序在内存中的所属空间)
    程序只有在运行的时候才会被加载进内存
    2.进程内部的划分
    进程不会直接执行,只是被当作分配内存资源的基本单位,真正的执行单位就是线程(执行路径),一个进程至少含有一个线程,多个线程就代表多个任务,多个执行路径,可以并发运行,所以它们之间存在一定的制约条件 eg:可能存在多个线程合作完成某个任务,可能访问资源存在顺序关系。加载程序代码进内存--从某个入口执行
    3.多线程存在的意义:并发执行,一段时间内可以同时执行多个任务
    注意:并发并没有同时执行多个任务,微观串行,宏观并行。CPU控制程序运行,负责调度线程的运行(分时间片调度线程执行--时间片很短)
    假如存在两个CPU,此时能够做到真正的并行执行--缺点还是没有足够的内存
    4.多线程的好处和弊端
    优点:能够解决多个程序一段时间内的并发执行
    缺点:多线程被CPU调度的等待时间加多
    5.目前只有一个线程--主函数线程(必须依赖于线程的执行),堆里面出现垃圾,垃圾回收线程
    JVM一开启就会启动多个线程eg:主线程,垃圾回收线程等
    线程的任务执行完成,线程就结束了,JVM会等着所有线程结束,JVM才会退出
    6.垃圾回收器并不会一遇到垃圾就回收,而是先判断堆内存的大小,根据内存大小决定是否进行堆内存回收
    7.主线程--仅仅存在时候,程序只有一条执行路径,按照代码书写的顺序执行(方法调用还是一个线程),JVM判断没有其他内容就直接关闭进程
    8.什么时候可能会想到使用多线程
    A-->B-->C 按照该顺序,但是B事件此时需要的循环时间花费大,所以此时就自定义一个线程,用来完成C时间的执行

    -----多线程具体学习-----底层的执行与系统相关(Thread里面的方法基本是与系统相关的本地方法)
    注意:关于为什么要继承Thread类,而不是直接创建Thread类对象
    原因是:创建线程为了创建执行路径,主线程其执行的任务都定义在main方法里面,自定义的线程其对应的任务应该定义在Thread类定义的run()方法里面,所以不同的线程必须要进行特殊的任务时候,必须重写run(),进而就必须继承Thread类。

    -----如何创建一个线程------
    * 继承Thread类(已经实现Runnable接口),重写run方法
    创建Thread子类的对象,启动线程 对象.start()并告诉JVM自动调用对象的run()方法
    注意:利用子类对象调用run()此时不是启动线程,而是方法调用
    CPU调动线程是随机的,所以执行的结果就是随机的
    getName()获取线程对象的名字
    Thread.currentThread()获取当前运行线程对象的引用
    * 多线程运行图解
    创建启动一个线程---就创建一个单独的路径(相当于每个线程有在进程的内存空间里面占有固定的空间,线程执行完后释放空间)
    eg:有3的线程名字分别为1,2,3,他们分别执行,他们各自执行自己的内容(假如)
    假如主线程出现异常,自会自己不执行下去,并不会导致其他线程的执行状态发生改变
    谁发生异常,那个线程就结束---用于分析多线程安全问题
    -----什么时候使用多线程----
    某个代码要被同时执行,比如打印循环--可以将这些代码的执行利用线程来实现
    让该类继承Thread类,重写run(){被多次执行的代码}。
    问题出现:假如该类以及继承一个父类,无法进行继承Thread类,可以采用第二种创建线程的方式。
    * 定义类实现Runnable接口,重写run()方法,创建Thread对象接受Runnable接口的子类对象
    (接口可以对类的功能进行扩展)
    MyThread implements Runnable{
    public void run(){线程体;}
    }
    MyThread mt = new MyThread();
    Thread t = new Thread(mt);--存在多态 t.start();
    第二种创建设计思想:持有接口的引用(调用第二种构造线程对象的构造方法)-看源码
    第二种创建线程好处
    * 在第一种方法中继承Thread()类,其实就是仅仅想使用run()方法,并没有想要继承Thread类里面的所有方法,此时我们就可以直接实现接口Runnable(只用重写一个run方法就可以了)
    * 第二个好处在要执行多次的类已经有父类的情况下,选择实现接口--避免单线程局限性
    所以创建线程的第二种方式比较常见
    * Thread类也是实现了Runnable接口

    ------线程的状态转化-------
    1.被创建状态---变成线程对象
    2.调用start被启动成为就绪状态--等待CPU的调度-有被执行的资格
    3.假如CPU调动--就变成运行状态--CPU正在处理该线程
    (就绪--运行 运行--就绪 运行(等待事件的发生/自己调用sleep休眠一定的时间)--阻塞 阻塞(被别的对象唤醒)--就绪)通过对象调用wait/notify方法(Object里面的方法)
    调用sleep()后会让出CPU的执行权,等醒来后,再继续在就绪队中排队等待调度
    注意:sleep()在那个线程体里面,那个线程休眠
    4.阻塞状态:释放执行权被CPU调度,放弃执行资格
    5.线程死亡:线程被强制结束stop/线程体执行完了
    6.线程启动后,不能重复启动---会发生异常

    ------多线程安全问题的引出------
    四个卖票卖完--多线程同时执行--
    1.方法一处理:继承Thread类,此时num会存在于4个线程对象中,总数400票
    可以静态处理num--但是这不太符合题目的要求
    2.方法2处理实现接口,但是只用创建一个Ticket对象,所以总数字就是100票
    3.多线程安全问题产生的原因
    * 多线程操作共享数据
    * 操作共享数据的代码有多条
    * 当一个线程在操作共享数据的多条代码中时候,又有其他线程参与其中,就会导致线程安全问题的产生
    ------多线程问题的解决办法-------
    本质就是防止一个线程在操作共享数据的时候,另外没有其他线程的参与
    具体的设计:
    就是将多线程操作共享数据的代码封装起来,当有线程执行代码的时候,不允许其他的线程访问,只有当该线程执行完后,别的线程才可以访问。
    1.对象锁synchronized修饰代码块--同步代码块--实现同步
    具体格式synchronized(对象){需要被同步的代码;}
    对象--this/其他任何对象
    观察结果:只有部分线程打印--原因就是其他的线程未抢到被执行的机会
    2.修饰方法--同步方法(需要被按照次序执行)---锁定的是该方法所属对象--也是一种封装
    锁是方法所属对象--this
    可以让线程1--使用同步代码块;线程2--使用同步方法,只要他们的锁定为同一个this,就可以实现线程1,2的同步:
    注意:eg:卖票例子的具体实现过程:
    1.创建2个卖票线程,以及本来就存在的主线程
    2.主线程运行,启动线程1,主线程休眠让出cpu执行权,线程1获得执行权,持有this锁进入run方法里面,先休眠(该过程不会释放锁),醒来后继续执行(或者),cpu分配的时间片结束后,让出cpu执行权。
    3.主线程修改Flag参数,线程2启动并获得执行可能执行到结束。

    -----同步代码块与同步方法的区别-----
    同步函数的对象锁---this
    同步代码块的锁---可以为任意的对象
    一般比较推荐使用同步代码块

    ----静态同步函数的锁----
    静态同步函数的锁:所属类的字节码文件被封装的为Class类型的对象--字节码文件对象
    获取该对象的方式:this.getClass()/Thicket.class(字节码文件对象具有静态属性class)

    ----同步使用的前提----
    同步并不能解决所有的线程安全问题,它解决的是问题必须具备以下两点
    1.程序中存在多个线程
    2.保证多个线程访问同一个资源时候使用相同的锁,否则就不能保证某个线程在访问该资源的时候,没有其他线程的进入。
    3.锁:其实本质就是保证线程在被CPU调度后,执行的过程中不会存在别的线程的进入
    (不管任何任何情况--休眠/时间片用完等情况,只要是线程处在同步中,就会保证只有一个线程在其中--一旦出了同步其他线程在获得调度权的情况下,就可以进入同步中)
    4.多个线程访问共享资源,有安全隐患,并不是每次都发生安全问题

    ---单例设计模式与多线程安全----
    单例设计模式
    1.懒汉式--延迟加载单例模式,先创建引用,调用get方法的时候,再创建对象--比较推荐
    2.饿汉式--创建对象,提供返回该对象的公共的方法
    3.对于懒汉式单例---加了同步方法,会每次都判断锁,费时间,所以加同步代码块,会先判断假如已经创建一个对象,不要判断锁,直接获取单例对象。

    ---死锁----
    1.常见形式之一同步嵌套--线程A在具备a锁情况下,还需要b锁,同时线程B在具备b锁情况下,还需要a锁,俩个线程互不相让--导致两个线程都不能进行下去

  • 相关阅读:
    jmeter(1)工具使用--L
    fiddler(17)插件
    fiddler(16)安卓抓包 、ios抓包
    fiddler(15)firefox
    fiddler(14)https抓包
    fiddler(13)弱网
    fiddler(12)断点
    fiddler(11)FiddlerScript-log-Timeline
    fiddler(10)Filter
    fiddler(9)辅助标签和工具(统计-检查器-自动响应-设计请求)
  • 原文地址:https://www.cnblogs.com/sun1993/p/7525570.html
Copyright © 2011-2022 走看看