欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

多线程的学习总结 较笼统

程序员文章站 2022-05-30 16:05:30
...
近段时间重温了java的并发,发现还蛮有意思的,现在总结一下大体的流程吧!
1、 为什么要并发
当计算机在处理应用的过程中,CPU、内存等并不是处于最佳状态(动力十足全力前进),这难免就会造成资源的浪费;在计算一个高精度高复杂性的科学计算时,就需要更快的处理速度,单线程有时会独木难支;在越来越丰富的界面化的应用中,用户的体验度就包括程序的响应速度,而单线程的程序显然难以达到要求。
2、共享对象的安全
在并发过程中,很多时候会用到线程间的通信,或者某个任务是由线程间的协作完成的,比如生产者/消费者问题,这时候,对于这种共享于两个或多个线程间的对象,就需要保证其“安全”。安全的定义其实很简单,那就是某个线程对共享对象的修改是可见的。在JAVA的定义中,为了提供更高的速度,是允许线程保存对象的复本的,只有在进入和离开同步代码块时,才会与原对象进行同步。
如何保证共享对象的安全呢,可以有以下方式:
  1> 共享对象的安全也即共享对象的状态属性安全,可以通过
      A> Volatile定义变量
      B> 使用automic原子变量类
      C> 将属性设为只读的final
      D> 在属性的更改方法中使用synchronized
      E> 在属性的更改方法中使用lock
注1:volatile定义的变量会直接从内存中读取并在修改后立即写回内存,禁止了java虚拟机对代码的优化,此类对象提供的读写均为原子操作,但自增操作等此类复合操作并非原子操作,不能保证该变量的安全。使用条件:新值不依赖之前的旧值,不依赖其它的状态变量,不需要放在synchronized等锁中。
注2:automic原子变量类在long,double等操作时有重要意义,对于64位的long,double类型数据写入时,会分别写入高位与低位,两次写入可能会导致安全问题。
注3:synchronized的锁其锁定的对象为
多线程的学习总结 较笼统
            
    
    博客分类: java基础 thread多线程exchangejava
注4:Lock 其实现类ReentrantLock提供了可定时的可轮询的可中止的锁,但该锁是显示的,即需要手动加锁与解锁。
  2> 还可以通过其它方法实现,比如使用ThreadLocal,或者将对象用作线程独占的不作为共享对象使用,或者使用线程安全的Collection。
注:ThreadLocal为每一个使用该变量的线程都提供一个变量值的副本,使每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突,使用put,get来存取。
3、线程的建立
  1> 创建线程的方式
      A> 实现Runnable接口,将执行代码块放入run方法中。
      B> 继承Thread类,重写run方法。
      C> 实现Callable接口,并实现call方法,该接口是用于有返回值的线程。
  2> 启动线程的方式
      A> 实现Runnable接口的类可以使用
            1. 以Runnable接口类的实例去实例化一个Thread对象,并调用该对象的start方法
            2. 实例化一个Executor的实现子类:
                  a) Executor.newCachedThreadPool  缓存0到无穷多个线程,用则建不用则毁
                  b) Executor.newFiledThreadPool  缓存min到max 个线程,自动管理个数
                  c) Executor.newScheduleddThreadPoolExecutor 可以定时执行,只支持相对时间
            执行executor.execute(Runnable)
      B> 继承Thread类的线程类,可以直接调用start方法启动线程
      C> 实现Callable接口的类需要使用Executor框架的子类,并调用submit方法来启动,在启动后会返回一个Future对象,该对象可以判定线程的状态:isDone,isCanneled,使用get方法取出线程的返回值。
4、线程的结束
  1> 设置结束状态位,在执行过程中不断监测该状态位的值,符合退出条件即退出。
  2> 使用异常结束,使用interrupt异常结束,这个异常在结束即将进入阻塞或已经阻塞的时候会立即执行,在正常运行时不会执行,但会对interrupted状态位置值,所以可以不断的监测该状态,并使用try-catch-finally块包围,在finally中释放相关资源。
5、线程的异常处理
异常是不会跨线程传递的。
  1> 在线程中或线程外捕获RuntimeException,加以处理
  2> Thread类可以设置setUncaughtExceptionHandler做异常处理
6、线程的协作
有时候,线程之间是相互配合操作的,比如生产者/消费者,所以就需要线程之间进行协作。线程之间的协作一般可以通过以下方式进行:
  1> 使用Object对象中的wait、notify、notifyAll进行
  2> 使用Condition对象中的await、signal、signalAll进行
  3> 使用线程的协作组件
7、线程的协作组件
线程中会有协作,比如生产者/消费者,以下是一些协作的组件
  1> CountDownLatch典型的应用场景是:有一个任务想要往下执行,但必须要等到其他的任务执行完毕后才可以继续往下执行。在初始化时设置一个countDown值,该值一经设定不可改变,当后继任务需要前驱任务的结果时,需要await,当countdown的值为0时,则await的线程会被唤醒并执行。
  2> CyclicBarrier允许一组线程互相等待,直到到达某个公共屏障点。典型的应用场景是:是水运中的分段转运法,它使任务在完成某一阶段时进行await,当所有的任务均进入await状态时,即进入下一阶段的运行。
  3> DelayBlokingQueue 存放的是一组实现了Delay接口的对象,因为Delay继承了Comparable接口所以Delay的实现类必须重写compareTo方法,其中delay时间最长的也即最紧急的放在队列头,依次以delay时间排序。这是一个阻塞式的队列。
  4> PriorityBlockingQueue 是具有优先级的队列,其中的对象也必须实现Comparable接口,也是阻塞式的队列。
  5> Semaphore 更像是一个厕所,进入足够多的人后就不允许再进入了,每次进入都必须获取通告证acquire,当出来后则需要交还通告证release。
  6> Exchanger 提供两个线程间直接交换对象的方法,这样可以使用对象在线程为为独占的,当使用完成后调用exchange方法将当前任务挂起,等另一个任务也执行此方法时进入对象的交换,交换完成后双方任务自动继续执行。

哈哈,总结的有点太概括了,回头再弄分述下
  • 多线程的学习总结 较笼统
            
    
    博客分类: java基础 thread多线程exchangejava
  • 大小: 15.6 KB