美文网首页
java并发编程 学习笔记

java并发编程 学习笔记

作者: nyle | 来源:发表于2016-07-24 16:55 被阅读63次

记一下学习过程的觉得需要注意的点吧

第二章、线程安全性

无状态对象一定是线程安全的
内置锁是可重入的,就是说获得锁的操作的粒度是一个『线程』,而不是一个『调用』。
synchronized 函数,是对类的实例加锁。

第三章、对象的共享

在程序中,可能编译过程中会进行重排序。就是对代码中的执行顺序可能进行改变,这样的优势是充分利用流水线的作用。 (这个有点可怕呀)

volatile
关键字可以保证变量的可见性,因为对volatile
的操作都在Main Memory中,而Main Memory是被所有线程所共享的,这里的代价就是牺牲了性能,无法利用寄存器或Cache。volatile
还有一个作用就是局部阻止重排序的发生

对于非volatile类型的64位数值变量double和long
jvm允许将64位的读操作和写操作分解成两个32位的操作,所以不考虑失效数据的问题,在多线程中共享
可变的long和double也是不安全的,除非用volatile来声明他们。(这个也要注意下,可能webApi中,会修改一个全局变量,这个时候long的修改可能会读到一个错误的值)

在构造函数中最好不要新建一个线程并启动,可以吧启动放在后续的函数中。因为可能在构造完成之前,线程就会访问到this的值。

线程封闭

  • ad-hoc线程封闭
    这个好像说完全自己在代码里注意
  • 栈封闭
    相当于用局部变量
  • Threadlocal类
    不同线程调用的一个Threadlocal变量不一样
第四章、对象的组合

没啥,主要注意加锁的时候,要加在一个锁上面,不要加错了

第五章、基础构建模块

Hashtable和Vector是同步容器
创建一个同步List Collections.synchronizedList(new ArrayList<Object>());

通过并发容器来代替同步容器,可以极大的提高伸缩性并降低风险
接下来介绍了一些并发容器:

  • cuncurrentHashMap 使用的是分段锁,实现了额外的原子操作,类似相等则移除之类的,保障他的迭代器不会影响。
  • copyOnWriteArrayList 每次修改的时候都会把底层数组复制一遍,这样保障他的迭代器不会影响。
  • LinkBlockList ArrayBlockList.是FIFO队列
  • PriorityBlockingQueue 是一个优先级的队列
  • 双端队列 Deque ,可以实现,生产者首先读取自己的队列,空了再去别人的队列尾部开始工作,降低了队列的竞争程度

中断
首先,忘掉Thread.stop方法。虽然它确实停止了一个正在运行的线程,然而,这种方法是不安全也是不受提倡的,这意味着,在未来的JAVA版本中,它将不复存在。
中断线程最好的,最受推荐的方式是,使用共享变量(shared variable)发出信号,告诉线程必须停止正在运行的任务。
因此,如果线程Object.wait, Thread.join和Thread.sleep三种方法之一阻塞,正确的停止线程方式是设置共享变量,并调用interrupt()(注意变量应该先设置)。如果线程没有被阻塞,这时调用interrupt()将不起作用;否则,线程就将得到异常(该线程必须事先预备好处理此状况),接着逃离阻塞状态。在任何一种情况中,最后线程都将检查共享变量然后再停止。Listing C这个示例描述了该技术。
http://www.cnblogs.com/simonshi/archive/2011/12/31/2308455.html 这个讲的还可以

同步工具类

  • CountDownLatch是一种灵活的闭锁实现,await会一直阻塞到,值为0.countDown会把值减1(闭锁,门一开始是关闭的,等待所需要的资源都初始化之后,会打开,并且一直打开)
  • FutureTask,Callable。一种有结果的Runnable.future.get() 可以获得
  • 信号量Semaphore
  • CyclicBarrier 感觉和countDownLatch差不多,只是可以重复使用
第六章、任务执行

Executor 任务执行框架
如果在程序中实现一个生产者消费者的设计,那么最简单的方式就是使用Executor

延时任务和周期性任务
Timer类和ScheduledThreadPoolExecutor。
Timer有一些缺陷,Timer在执行任务时只会创建一个线程,如果某个任务执行时间过长,将会影响其他的TimerTask的精确性。而且如果TimerTask抛出了一个未检查的异常,那么Timer将变现出糟糕的行为。
在java 5.0或更高的jdk中,将很少使用Timer。

如果要构建自己的调度系统,可以使用DelayQueue。(可以设置过期时间,然后take的时候,只能取出到了时间的)

可以用ExecutorService的submit(callable a)方法来得到一个Future,然后future.get()得到返回值。但是这里所有的都会在future.get()处等待
可以使用ExecutorCompletionService来进行处理,在提交多个task之后,起一个轮训,取completion.take(),这样可以获取完成了的线程。

为任务设置时限:
1.可以使用future.get(long timeout, TimeUnit unit),然后catch住TimeOutException

对于要对多个futureTask设定实现,可以使用invokeAll(List<Callable> **, long timeOut, TimeUtil unit)

相关文章

网友评论

      本文标题:java并发编程 学习笔记

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