线程和线程池
首先线程有守护线程和用户线程两种,区别就是用户线程是否保持程序的运行状态。当程序在运行时,必定有一个或以上的线程是用户线程,而当程序结束时,所有守护线程也都将被关闭。使用Thread.setDaemon(ture)可以把线程标记为守护线程,默认线程状态继承自创建它的线程。线程的两种创建方法不多说了。
线程安全一般指的是共享变量被多个线程访问读写造成的数据不一致或者是数据不完整性。一般有如下几种方法可供参考:
1.synchronized方法,提供只能供一个线程访问的类,方法或语句块,控制变量的修改是在可控范围内的。
2.lock方法,可使用java.util.concurrent.locks包内的读写锁或重入锁来控制。
3.ThreadLocal变量来为每个线程单独获取一份变量的拷贝。
4.机器指令级的原子性操作,如java.util.concurrent.atomic包中的变量。用CAS(compare and swap)来保证数据更新的有效性。即无锁机制来保证高并发量时的性能,保持高的吞吐量。
内部锁、外部锁和无锁机制的比较
首先比较内部锁和外部锁
内部锁是指用synchronized的方式,java对象内置的锁对象来进行线程同步协调,外部锁是指使用实现了lock的对象,如ReentrantLock或者ReentrantReadWriteLock。一般认为类 ReentrantLock
被作为 Java 语言中 synchronized
功能的替代,但是事实上,如果没有明显的理由(如出现性能瓶颈),还是用synchronized的方式更好一些。
synchronized更加安全,它功能比较单一,在对对象的锁定之后,无论是程序运行出了synchronized语句,还是因为异常等原因,都能保证锁是被释放掉了的。但是ReentrantLock对象的锁需要在finnally语句中显式地释放。
ReentrantLock更加灵活,功能也更加丰富,属于高级用法。性能上也更加优越。
锁机制和无锁机制的比较
锁机制经常需要面对死锁,优先级反转,饥饿,活锁等问题,而且有时候出现死锁等情况时比较难以排查和处理,这时候就会大大不仅影响性能,而且可能会使程序整体停滞不前。所以无锁机制的引入能够有效地避免这些问题,而且相对于锁机制,等待时间可能会更少,性能会得到提高。无锁机制算法的一个提前是原子性操作。
5.还没想好
jdk中本身提供了线程池的实现,用起来很方便。使用jdk提供的线程池一般分为4步,1.创建线程对象,2.创建线程池,3.用线程池执行线程对象,4.最后线程池关闭。
大致上有这么几种线程池
newFixedThreadPool(n):创建一个可重用的固定线程数的线程池
newCachedThreadPool():有可用的线程可用时候会去用它们执行任务,否则创建新的线程加入到线程池中。
newScheduledThreadPool:定期执行或给定延迟命令运行
考虑到线程池中的线程满了之后的情况,线程会加入等待队列中,等待队列一般有两种策略来应对,一 是用linkedquere无限加入等待队列,二 有个数限制的arrrayquere也满了的话则会报reject错。