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