美文网首页
初识并发编程

初识并发编程

作者: 925781609 | 来源:发表于2019-02-27 22:07 被阅读0次

    1. 并发与并行:

          1) 并发: 一段时间内能同时处理多个请求

          2) 并行: 多个CPU同时去执行

    2. 什么时候应该使用多线程:

          1) 需要等待网络、I/O响应导致耗费大量的执行时间,而且对实时性要求也不高,可以采用异步线程的方式来减少阻塞

          2) 通过并行计算提高程序执行性能

    3. 线程状态:

          1) new: 线程刚被创建,还没有调用start方法

          2) runnable: 获得锁正在执行(running)或准备执行(ready, 由于cpu切换走干别的了)

          3) blocked: 没获得到锁,被阻塞

          4) waiting:    已经获得锁、正在运行的线程,调用wait, join,park 进入等待, notify,upark从等待状态返回

          5) time_waiting: 超时等待,和waiting相比,多一个sleep进入超时等待,多一个超时时间到返回。 wait释放锁,sleep不释放锁

          6) terminated: 线程执行完毕

       ( 针对这个图稍微有一点疑问, 对于Object.wait(),线程会释放锁,那么从waiting状态返回时会先通过cas自选,如果额能获取锁进入runnable状态, 获取不到锁应该进入blocked状态 )

    4. 线程的启动:

          start是native方法,最终告诉jvm调用run方法

    5. 线程的停止:

          1) Thread过期的stop,resume, suppend API, 停止线程时,不会释放已经占有的资源,例如锁

          2) interrupt方法:

                i. 其他线程调用该线程的interrupt方法,设置该线程的中断标志位, 至于什么时候中断,由该线程决定

      可以通过isInterrupt判断中断标志位是否被配置,如果配置了将程序暂停

    ii. 遇到低优先级的block状态时,比如object.wait(),object.sleep(),object.join()。

      interrupt通过 unpark 去唤醒出于waiting状态的线程,并设置中断标识。 wait/sleep/join会throw一个InterruptedException, 抛出异常后,会清除中断标志位

    6. 线程安全性问题:

      1) JMM:

      i. 定义了共享内存系统中多线程程序读写操作行为的规范,来屏蔽各种硬件和操作系统的内存访问差异

      ii. 共享变量是指实例对象、静态字段、数组对象等存储在堆内存中的变量。而对于局部变量这类的,属于线程私有,不会被共享 。

      2) 线程安全性问题:

      i. 可见性:一个线程改变工作内存中的变量,另一个线程立刻可见

      ii. 原子性:多线程内自增某一个变量

      iii. 有序性:  编译器优化+ 指令重排序, 执行顺序和代码顺序不一致,前提是不影响单线程代码语义,却会影响多线程并发执行的正确性

    7. 多线程间的通信:

      1) 共享内存:

      主内从存放共享变量、多个线程的工作内存会缓存共享变量, 线程对工作内存的修改会同步到主内存中(什么时候同步不一定,会引起可见性问题)

      2) 消息传递: wait/notify

    8.Thread,Runnable,Callable:

      1)Runnable 和Callable是两个接口,分别有run和call两个方法, Runnable方法有返回值, Callable方法没有返回值

      2)Thread实现runnable, runnable通过Thread实现多线程,由一个runnable创建的多个Thread间会共享数据。

            Thread是对象, runnable接口, runnable可以解决多继承的问题

        i. Thread

      执行结果如下, 可以看到三个t1,t2,t3 三个线程各卖5张票,三个线程彼此独立

        线程t1卖第4张票

        线程t1卖第3张票

        线程t1卖第2张票

        线程t1卖第1张票

        线程t3卖第4张票

        线程t2卖第4张票

        线程t2卖第3张票

        线程t2卖第2张票

        线程t2卖第1张票

        线程t2卖第0张票

        线程t3卖第3张票

        线程t3卖第2张票

        线程t3卖第1张票

        线程t3卖第0张票

        线程t1卖第0张票

    ii. Runable

        执行结果如下 ,可以看到Runnable中的count在多个线程中共享,并且出现并发问题:

        线程t1卖第3张票

        线程t2卖第2张票

        线程t2卖第0张票

        线程t3卖第3张票

        线程t1卖第1张票

        现在对为什么Runnable中的count能够在多线程中共享,首先看Thread中的源码,可以看到多个Thread中的target引用同一个Runnable对象,Thread的run方法,最终调用的就是同一个Runnable对象的run方法,所以Runnable中的数据会被共享

    iii. Callable:

    Callable 可以有返回结果,通过Future或者FutureTask来获得异步执行的结果, FutureTask扩展RunnableFuture, RunableFuture 扩展 Runnable和Future

    使用示例如下:

        Callable+ Future 最终也是以Callable+FutureTask实现的, executorService.submit(myCallable)的源码如下:

    相关源码:https://github.com/925781609/JavaCodeLibary/tree/master/src/main/java/com/liuil/codelibary/multithread

    相关文章

      网友评论

          本文标题:初识并发编程

          本文链接:https://www.haomeiwen.com/subject/auvquqtx.html