同步:多个线程对同一资源有先后顺序的依次执行。
异步:多个线程同时对同一资源进行竞争,并发执行。
产生多线程并发安全问题的原因是:多线程并发操作同一数据
解决多线程并发安全问题的办法:将异步的操作转为同步操作
synchronized:限制多线程并发时访问该作用域。可以对方法上锁,也可以用来对一段代码上锁。它只是一个对象锁的标识,不能继承它的特性和功能。
synchornized(同步监视器——锁对象){
同步内容
}
多线程看到的对象锁必须是同一个对象,通常锁对象为this
同步锁的原理:
每个java对象都可以做一个实现 同步的锁,线程进入同步代码块之前会自动获得锁,并且在退出同步代码块时自动释放锁,而且无论是通过正常途径退出还是通过抛出异常退出都一样,获得内置锁的唯一途径就是进入由这个锁所保护的同步代码快或方法。
当两个线程在同一个地方访问同一个对象时,称为同步锁
当两个线程在不同的地方访问同一对象时,称为互斥锁,即只能有一个线程访问对象,另一个线程等待。
wait():当条件不满足时,则等待。当条件满足时,该条件的线程被唤醒
notify():随机通知、唤醒一个在当前对象上等待的线程
notifyAll():解除所有在当前对象身上等待的线程
wait/notify(等待机制)和synchornized(锁机制)是密切相关的,即wait/notify应和synchornized同时使用。等谁就锁谁。
将集合或Map转换为线程安全的,用Collections的静态方法:
synchornizedList();获取线程安全的List集合
synchornizedMap():获取线程安全地Map
synchornizedHashSet():获取线程安全的Set集合
线程池(ExcutorService):由线程组成的集合。
用途:重用线程;控制线程数量
原理:当服务器接收到一个客户请求后,就从线程池中取出一个空闲的线程为之服务,服务完后不关闭线程,而将该线程还回到线程池中。
线程池有以下几种实现策略:
Executor.newCachedThreadPool():
创建一个可根据需求的新线程池,但是在以前构造的线程可用时,将重用它们
Executor.newFixedThreadPool(int nThreads):
创建一个可重用nThreads个线程的线程池,以共享的无界队列方式来运行这些线程
Executor.newScheduledThreadPool(int corePoolSize):
创建一个线程池,它可以安排给定的延时corePoolSize后运行命令或者定期执行。
Executor.newSingleThreadPool():
创建一个使用单个worker线程的Executor,以无界队列方式来运行线程
线程池的线程分配方法:execute(Runnable runn):为runn分配空闲线程,使之运行。
BlockingQueue(双缓冲队列):其内部使用两条队列,可允许两个线程同时向队列一个做存储,一个做取出操作。是一个接口,可保证并发安全的同时提高存取效率。
常用的实现类有:
ArrayBlockingDeque(int n):创建大小为n的BlockingDeque,是以FIFO顺序排序的。
LinkedDeque():若带参数则大小受限,若不带参数,则为最大容量为Integer.MAX_VALUE的不定大小的BlockingDeque,以FIFO顺序排序。
PriorityBlockingDeque():类似LinkedBlockingDeque,但是以对象的自然顺序或构造的comparator()存储。以从小到大的顺序取。所以对象必须能比较大小。
SynchornousQueue():特殊的BlockingQueue,对其操作必须是放和取交替完成的。