多线程

1.什么进程?
 *         值得就是正在运行的程序,是系统进行资源分配和调用的独立单位
 *         每一个进程都有它自己的内存空间和系统资源
2.什么线程?
 *         是进程中的每个顺序控制流,是一条执行路径
 *         一个进行如果只有一条执行流程,则为单线程
 *         一个进程有多条执行路径,则为多线程
3.什么是并行?什么是并发?
 *          前者是逻辑上同时发生,指在某一个时间内同时运行的多个程序
 *          后者是物理上同时发生,指在某一个时间内同时运行多个程序
4.java的运行原理?
 *         由java命令启动JVM,JVM启动就相当于启动了一个进程
 *         接着该进程创建了一个主线程去调用main()方法
5.需求:我们要实现多线程的一个程序,问   我们要如何进行实现?
 *         由于线程是依赖进程而 存在的,所以我们应该先创建一个进程出来,
 *         而进程是由系统进行创建的,所以我们应该去调用系统工程,创建一个进程
 *         java是不能直接去调用系统功能的,所以我们没办法直接实现多线程的程序
 *         但是呢,java可以去调用C/C++写好的程序来实现多线程的
 *         由C/C++去调用系统功能创建进程,然后由java去调用这个方法

 

继承Thread类 步骤:
    1.自定义MyThread,继承Thread类
    2.在MyThread中重写run()方法
        为什么要重写run()方法?
            不是类中的所有代码都需要被线程去执行的.
            而这个时候呢,为了区分哪些代码能够被线程执行。java中提供了Thread类中的run()
            用来包含哪些被线程执行的代码
    3.创建对象
    4.启动线程

run()  他是一个单线程,直接可以当做普通方法去使用,
如果我想 执行一个多线程  那么另一个方法  start()
      
问  start()和run的区别?
    run()仅仅是封装线程执行的代码,直接调用时可以是 一个普通的方法
    start()首先启动了进程,然后由jvm去调用该线程的run()方法

Thread类的基本获取和设置线程的方法:
    1.public final String getName()  获取线程的对象名称
        2.public final void  setName(String name):设置线程的名称
我们也可以通过构造方法去给线程起名称
问:
    如果获取了main方法所在的线程名称?
    例如:针对如果不是Thread类的子类中如何获取线程名称对象呢?
    1public static Thread curretThread()  返回当前正在执行的线程名称
    2.Thread.curretThread().getName()

我们要获取main()方法 所在的线程对象名称  如何解决?
    //遇到这种情况呢,Thread类提供了一个很好玩的方法
    1.public static Thread currentThread()  返回当前正在执行的线程对象

线程的调度
    假如我们的计算机只有一个cpu,那么CPU在某一个时刻只能执行一条指令
    线程只有得到CPU时间片才能有使用权,才能执行指令
线程的两种调度策略
    1.分时调度策略: 所有线程轮流的去使用CPU的使用权,平均进行分配,每个线程占用CPU的时间
    2.抢占式调度策略:优先让级别高的线程使用CPU,如果线程的优先级相同,那么他们会随机选择一个,优先级高的线程获取CPU
       时间片的调度策略会多一些.
        注意:java中用的就是抢占式调度模型

 

优先级我们的线程是没有设置优先级的,肯定是有默认的优先级,
    在java中默认的优先级是5
    线程优先级的范围:1-10
    线程优先级仅仅表示线程获取的CPU时间片的几率高,但是要在次数比较多,或者多次运行的时候才能看见更好的效果

设置线程优先级的方法?
    public final  void serPRriority(int NewPriority) : 更改线程对的优先级   

 

线程的睡眠方法:
    public static void sleep(long milis):在指定的毫秒数内让当前正在执行的线程休眠(暂停一会再去执行)
注意:
    在sleep中 传入值是毫秒值

 

线程的加入方法:
        1.public final void  join():等待该线程或者终止
    大体的概念:
        我调用了这个方法,必须线程执行完毕之后,其他的线程才能调用

 

线程的中断与结束方法:
    public final stop():让线程停止,过时间了,但是还可以使用
    public void interrupt():中断线程,把线程装填停止,并抛出一个INTERRUPTEDEXCEPTION

 

创建线程的另一种方法 Runnable接口的类,该类也会去实现run()方法,然后可以分配该类的实例,

 

实现Runnable接口实现Runnable接口的好处:
    1.可以避免由于JAVA当继承带来的局限性
    2.适合多个相同的程序的代码去处理同一个资源的问题,把线程同程序的代码、数据有效的进行分离,较好的体现了面向对象的设计思想

实现Runable接口的步骤
    1.定义一个MyRunnable,实现Runable接口
    2.在MyRunnable中重写run()方法
    3.创建MyRunnable类的对象
    4.创建Thread类的对象,把MyRunnable对象作为构造方法的参数
    5.启动线程
使用Runnable接口的好处:
    不影响MyRunnable继承其他的类

 

同步锁的弊端1.效率比较低
    2.容易产生死锁
       例如:
    两个或者两个以上的线程在争夺资源的过程中,发生了一种互相等待的现象
      举例:
    中国人、美国人吃饭案例
    正常情况下:
        中国人:一双筷子
        美国人:一个刀一个叉
    现在的问题:
        中国人:一只筷子 一个刀
        美国人:一只筷子 一个叉
线程之间的通信:
    针对同一个资源的操作有不同种类的类型
    只出不进:电影院卖票(八佰、金刚川)
    可进可出:早餐店(生产者:厨师  消费者:顾客)

 

Lock锁背景 :
    虽然我们可以理解同步代码块和同步方法的所对象,但是我们并没有看见那块上了锁,并在哪里释放了锁
    为了更好更清晰的表达如何并如何释放锁,JDK5之后提供了一个新的锁对象,LOCK
               lock是接口不能直接序列化,这里采用他的实现类ReentrantLock来实例化
方法ReentrantLock创建一个ReentrantLock的实例
    加锁解锁的方法:
    方法名                说明
    void lock()       获得锁
    void unlock()   释放锁

 

线程池线程池的基本背景
        程序启动一个新的线程成本是很高的,因为它涉及到与操作系统进行交互。而使用线程池可以很好的提高性能,尤其是
             当程序中要创建大量的生存很短的线程时,就要考虑使用线程池
      线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中称为空闲状态,等待下一个对象来使用
     java内置支持线程池
    线程是使用进程的资源,所以每次开启一个线程,它的成本是比较高的,所以使用线程池,就能解决这个问题
    如何使用线程池?
    Executors工厂来产生线程池,如一下几个方法
    1.public static ExecutorService newCachedThreadPool()开启具有缓存功能的线程池
    2.public static ExecutorService newFixedThreadPool(int nThreads) 创建爱你多少个线程池
    3.public static ExecutorService newSingleThreadExecutor()创建单个的线程池
    
        这些方法的返回值是ExecutorService对象,该对象表示一个线程池..可以执行Runnable对象或者Callable对象代表的线程.
  步骤:
    1.创建线程池对象
    2.创建Runnable实例
    3.提交Runnable实例
    4..关闭线程池
线程池的好处
    线程池里面的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲装填,等待下一个对象来使用

 

实现Callable接口好处
        1.可以有返回值
        2.可以抛出异常
    弊端
        代码比较复杂,所以一般不用

posted @ 2020-12-29 10:01  芒果不氓  阅读(99)  评论(0编辑  收藏  举报