多线程基础

  • 多线程
  1. yeild是个native静态方法,这个方法是想把自己占有的cpu时间释放掉,然后和其他线程一起竞争
  2. 线程挂起,挂起(suspend)和继续执行(resume)线程。suspend()不会释放锁,直到被其他线程resume
  3. Thread类中的join方法的主要作用就是同步,它可以使得线程之间的并行执行变为串行执行,如:程序在main线程中调用t1线程的join方法,则main线程放弃cpu控制权,并返回t1线程继续执行直到线程t1执行完毕,main线程再继续执行。join方法实现原理调用相应线程的wait方法进行等待操作的
  4. synchronized有三种加锁方式:

指定加锁对象:对给定对象加锁,进入同步代码前要获得给定对象的锁。

直接作用于实例方法:相当于对当前实例加锁,进入同步代码前要获得当前实例的锁。

直接作用于静态方法:相当于对当前类加锁,进入同步代码前要获得当前类的锁。

  1. 如果这个线程调用了wait方法,它就处于一个Waiting状态。进入Waiting状态的线程会等待其他线程给它notify,通知到之后由Waiting状态又切换到Runnable状态继续执行。当然等待状态有两种,一种是无限期等待,直到被notify。一直则是有限期等待,比如等待10秒还是没有被notify,则自动切换到Runnable状态。
  2. 终止线程,Thread.stop() 不推荐使用,它将会立即停止掉线程
  3. 线程中断,Thread.interrupt()只是改变了中断状态, 即Thread.isInterrupted()将返回true,并不会使程序停止
  4. Volatile 对于这个成员变量不能保存它的私有拷贝,而应直接与共享成员变量交互。在多线程环境下,线程可以将线程间共享的变量保存在本地内存(如寄存器)中,而不是从内存中读取,这就可能会引发不一致的问题,而volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值
  5. ReentrantLock感觉上是synchronized的增强版,synchronized的特点是使用简单,一切交给JVM去处理,但是功能上是比较薄弱的。在JDK1.5之前,ReentrantLock的性能要好于synchronized,由于对JVM进行了优化,现在的JDK版本中,两者性能是不相上下的。如果是简单的实现,不要刻意去使用ReentrantLock。相比于synchronized,ReentrantLock在功能上更加丰富,它具有可重入、可中断、可限时(超时不能获得锁,就返回false,不会永久等待构成死锁)、公平锁(这个锁能保证线程是先来的先得到锁。虽然公平锁不会产生饥饿现象,但是公平锁的性能会比非公平锁差很多,不公平的锁可能会产生饥饿现象)等特点。
  6. Condition与ReentrantLock的关系就类似于synchronized与Object.wait()/signal()
  7. await()方法会使当前线程等待,同时释放当前锁,当其他线程中使用signal()时或者signalAll()方法时,线 程会重新获得锁并继续执行。或者当线程被中断时,也能跳出等待。这和Object.wait()方法很相似,https://my.oschina.net/hosee/blog/607677
  8. ReadWriteLock是区分功能的锁。读和写是两种不同的功能,读-读不互斥,读-写互斥,写-写互斥。这样的设计是并发量提高了,又保证了数据安全
  9. CountDownLatch,倒数计时器,countDown()、await()
  10. ConcurrentHashMap 我们知道HashMap不是一个线程安全的容器,最简单的方式使HashMap变成线程安全就是使用Collections.synchronizedMap,它是对HashMap的一个包装 public static Map m=Collections.synchronizedMap(new HashMap()); 同理对于List,Set也提供了相似方法。但是这种方式只适合于并发量比较小的情况,它会将HashMap包装在里面,然后将HashMap的每个操作都加上synchronized。
  11. 在 ConcurrentHashMap内部有一个Segment段,它将大的HashMap切分成若干个段(小的HashMap),然后让数据在每一段上Hash,这样多个线程在不同段上的Hash操作一定是线程安全的,所以只需要同步同一个段上的线程就可以了,这样实现了锁的分离,大大增加了并发量。   在使用ConcurrentHashMap.size时会比较麻烦,因为它要统计每个段的数据和,在这个时候,要把每一个段都加上锁,然后再做数据统计。这个就是把锁分离后的小小弊端,但是size方法应该是不会被高频率调用的方法。
  12. Callable类和Runable类相似,但是区别在于Callable有返回值
  13. Executors  ThreadPoolExecutor是线程池的一个重要实现  https://my.oschina.net/hosee/blog/614319
  14. ForkJoin  fork/join类似MapReduce算法,两者区别是:Fork/Join 只有在必要时如任务非常大的情况下才分割成一个个小任务,而 MapReduce总是在开始执行第一步进行分割。看来,Fork/Join更适合一个JVM内线程级别,而MapReduce适合分布式系统
  15. 单例模式  https://my.oschina.net/hosee/blog/614826
  16. NIO和AIO  

A,使用非阻塞的NIO (读取数据不等待,数据准备好了再工作)

B,一个Channel可以和文件或者网络Socket对应

C,selector是一个选择器,一个线程可以对应一个selector,而一个selector可以轮询多个Channel,而每个Channel对应了一个Socket;当selector调用select()时,会查看是否有客户端准备好了数据。当没有数据被准备好时,select()会阻塞。平时都说NIO是非阻塞的,但是如果没有数据被准备好还是会有阻塞现象。只有在数据准备好时,这个Channel才会被选择。这样NIO实现了一个线程来监控多个客户端。

C,selectNow()与select()的区别在于,selectNow()是不阻塞的,当没有客户端准备好数据时,selectNow()不会阻塞,将返回0,有客户端准备好数据时,selectNow()返回准备好的客户端的个数。

D,总结:NIO会将数据准备好后,再交由应用进行处理,数据的读取/写入过程依然在应用线程中完成,只是将等待的时间剥离到单独的线程中去。

E,AIO的特点:读完了再通知我;不会加快IO,只是在读完后进行通知 ;使用回调函数,进行业务处理

F,NIO是基于块(Block)的,为所有的原始类型提供(Buffer)缓存支持,增加通道(Channel)对象,作为新的原始 I/O 抽象

https://my.oschina.net/hosee/blog/615269

  1. 锁优化的思路和方法总结一下:

减少锁持有时间

减小锁粒度(将大对象,拆成小对象,大大增加并行度,降低锁竞争)

锁分离(锁分离就是读写锁ReadWriteLock,根据功能进行分离成读锁和写锁,这样读读不互斥,读写互斥,写写互斥,即保证了线程安全,又提高了性能)

锁粗化(为了保证多线程间的有效并发,会要求每个线程持有锁的时间尽量短)

锁消除( 锁消除是在编译器级别的事情。在即时编译器时,如果发现不可能被共享的对象,则可以消除这些对象的锁操作。 )

  1. 有时可以用ThreadLocal代替锁的方式, 由于SimpleDateFormat并不线程安全的,每个线程在运行时,会判断是否当前线程有SimpleDateFormat对象,如果没有的话,就new个 SimpleDateFormat与当前线程绑定

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值