专栏首页技术圈JAVA中常见的API比较

JAVA中常见的API比较

object的常见方法:

clone(),equals(),hasCode(),notify(),notifyAll(),toString(), finalize(),wait()

Vector、ArrayList、LinkedList的区别

结构上: Vector、ArrayList是一种类似数组的数据结构,更准确的应该说是顺序表。LinkedList则是以链表的方式进行存储。 区别:Vector不能够存储null,而ArrayList可以存储null。 效率上:从底层实现就可以看出,Vector、ArrayList方便查找,不方便插入和删除,而LinkedList则方便插入和删除,不方便查找。 线程安全上: Vector是线程安全的,而ArrayList和LinkedList是线程不安全的。如果程序本身是线程安全的,也就是说没有多个线程是共享访问的,选择Vector的效率要比ArrayList高。 节省空间上: ArrayList是填满的时候会自动进行扩充,Vector也是这样,但是ArrayList会自动扩充容器的50%,而Vector则会扩充容器的100%,显然是ArrayList更节省空间。 另外,从图中也可以看出LinkedList还实现了Queue接口,因此也就是具有了Queue接口的方法,比如offer(),peek(),poll()等方法。

sleep()和wait()的方法

之前在多线程中提到过两者的区别。这里希望能更为详细的总结一下 wait()是object的方法,包括在内的notify(),notifyAll()都是object的方法,是所有对象都有的方法。 sleep()是线程类Thread()独有的方法,并且是类方法,无论new()出多少个线程实例,sleep()方法都是被共享的。 sleep()被同步中所调用,这句话的意思就是说调用sleep的线程是拿到对象锁的线程,同样的wait()也是这样,只有拿到对象锁的线程才有资格调用sleep()或者是wait()。 在线程状态切换中,线程调用了sleep(),仍然会持有对象锁,会导致线程睡眠,进入阻塞状态。达到指定睡眠时间后,也就是睡眠结束后尽心可执行状态,重新参与CPU的抢夺。但在sleep的过程中过程中有可能被其他对象调用它的interrupt(),产生InterruptedException异常,如果你的程序不捕获这个异常,线程就会异常终止,进入TERMINATED状态,如果你的程序捕获了这个异常,那么程序就会继续执行catch语句块(可能还有finally语句块)以及以后的代码。 wait()会释放对象锁,放入等待队列,也就是等待阻塞。掌握了对象锁的线程在线程结束后调用notify或者是notifyAll()唤醒等待队列中的一个线程,这个线程就从等待阻塞切换到同步阻塞状态,等待当前线程结束。 notify/notifyAll()执行后,并不立即释放锁,而是要等到执行完临界区中代码后,再释放。故,在实际编程中,我们应该尽量在线程调用notify/notifyAll()后,立即退出临界区。即不要在notify/notifyAll()后面再写一些耗时的代码。

Synchronized 和Lock

在之前的文章中写过Synchronized,但是对Lock的基本没有提及 Synchronized是jdk1.2以来一直存在的,而Lock是jdk1.5增加的。 至于为什么在Synchronized又新增了Lock,这是因为在资源竞争激烈的条件下,Synchronized会使得性能下降十几倍。 使用了Synchronized的情况下,只有线程释放对象锁后,其他线程才能够继续执行,这也就意味着在高并发情况下,效率会很慢。 synchronized限制: 1. 它无法中断一个正在等候获得锁的线程,也无法通过投票得到锁,如果不想等下去,也就没法得到锁。 2.synchronized 块对于锁的获得和释放是在相同的堆栈帧中进行的。但是,确实存在一些更适合使用 非块结构锁定的情况。 在JDK 官方文档中提到: ReentrantLock是“一个可重入的互斥锁 Lock,它具有与使用 synchronized 方法和语句所访问的隐式监视器锁相同的一些基本行为和语义,但功能更强大。 ReentrantLock 将由最近成功获得锁,并且还没有释放该锁的线程所拥有。当锁没有被另一个线程所拥有时,调用 lock 的线程将成功获取该锁并返回。如果当前线程已经拥有该锁,此方法将立即返回。可以使用 isHeldByCurrentThread() 和 getHoldCount() 方法来检查此情况是否发生。 更重要的一点是synchronized的对象锁是在线程执行结束自动释放,而lock的需要程序员手动释放锁。这也就意味着对象锁的获得和释放都可以由编码 人员自行掌握。

volatile和synchronized的区别

volatile本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取; synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。 volatile仅能使用在变量级别;synchronized则可以使用在变量、方法、和类级别的 volatile仅能实现变量的修改可见性,不能保证原子性;而synchronized则可以保证变量的修改可见性和原子性 volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞。 volatile标记的变量不会被编译器优化;synchronized标记的变量可以被编译器优化

HashTable、HashMap,TreeMap,ConcurrentHashMap,ConcurrentSkiplistMap

继承关系上: HashTable的父类是Dictorinary,而HashMap的父类是AbstractMap,两者都实现了map接口。HashTable遍历通过的是Enumeration,而HashMap则是Iterator实现的。 TreeMap基于红黑树(一种自平衡二叉查找树)实现的,时间复杂度平均能达到O(log n)。 HashMap是基于散列表实现的,时间复杂度平均能达到O(1)。 ConcurrentSkipListMap是基于跳表实现的,时间复杂度平均能达到O(log n) 当数据量增加时,HashMap会引起散列冲突,解决冲突需要多花费一些时间代价,故在f(n)=1向上浮动。 随着数据量的增加,HashMap的时间花费小且稳定,在单线程的环境下比TreeMap和ConcurrentSkipListMap在插入和查找上有很大的优势 (1) TreeMap与HashMap相比较 Ø HashMap里面存入的键值对在取出的时候是随机的,它根据键的HashCode值存储数据,根据键可以直接获取它的值,具有很快的访问速度。在Map 中插入、删除和定位元素,HashMap是最好的选择。

Ø TreeMap取出来的是排序后的键值对。插入、删除需要维护平衡会牺牲一些效率。但如果要按自然顺序或自定义顺序遍历键,那么TreeMap会更好。 (2) TreeMap与ConcurrentSkipListMap相比较

Ø Skip list(跳表)是一种可以代替平衡树的数据结构,默认是按照Key值升序的。Skip list让已排序的数据分布在多层链表中,以0-1随机数决定一个数据的向上攀升与否,通过“空间来换取时间”的一个算法,在每个节点中增加了向前的指针,在插入、删除、查找时可以忽略一些不可能涉及到的结点,从而提高了效率。 从概率上保持数据结构的平衡比显示的保持数据结构平衡要简单的多。对于大多数应用,用Skip list要比用树算法相对简单。由于Skip list比较简单,实现起来会比较容易,虽然和平衡树有着相同的时间复杂度(O(logn)),但是skip list的常数项会相对小很多。Skip list在空间上也比较节省。一个节点平均只需要1.333个指针(甚至更少 线程安全:HashTable是线程同步的,key、value都不能为空。而HashMap是线程不同步,允许key、value值为空。在多线程情况下,如果使用HashMap,一定考考虑同步的问题,加锁,或者是Collections.synchronizedMap()来创建线程安全的对象。 哈希值的使用不同: HashTable object有hashCode()方法

int hash = key.hashCode();
int index = (hash&0x7FFFFFFF)%table.length;

HashMap 重新计算hashCode,用与代替求模

最后我们要说的是ConcurrentHashMap,ConcurrentHashMap是HashMap线程安全的实现。 一方面HashMap加锁时是对整个对象进行加锁,而ConcurrentHashMap是局部加锁。把整个Map分成如果各Segment,在put或者是get时利用key.hashCode()等一系列操作计算出应该从哪一个Seg中取或者是放入到哪一个Seg中。从而在性能上相对于HashMap中有很大提升。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Java多线程--线程各状态如何进行切换

    1、新建状态(New):新创建了一个线程对象。 2、就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于...

    张凝可
  • Java 同步 synchronized与lock

    实现线程同步一个使synchronized关键字,一个是通过对象lock. Lock 在jdk 1.5才出现的,在一定程度上缓解了synchronized同...

    张凝可
  • Java 多线程---基本概念

    ** 进程本质是执行中的程序。 线程是程序中流控制。本身是不能执行的,只能使用分配给程序的资源。 进程-线程 一个进程可以包含一个或者多个线程,...

    张凝可
  • 高级java必须清楚的概念:原子性、可见性、有序性

    原子性、可见性、有序性是多线程编程中最重要的几个知识点,由于多线程情况复杂,如何让每个线程能看到正确的结果,这是非常重要的。 原子性 原子性是指一个线程的操作是...

    Java技术栈
  • 谈谈java的ThreadLocal

    简单介绍 ThreadLocal一般称为线程本地变量,它是一种特殊的线程绑定机制,将变量与线程绑定在一起,为每一个线程维护一个独立的变量副本。通过Thread...

    Spark学习技巧
  • SpringBoot开发案例之多任务并行+线程池处理

    前几篇文章着重介绍了后端服务数据库和多线程并行处理优化,并示例了改造前后的伪代码逻辑。当然了,优化是无止境的,前人栽树后人乘凉。作为我们开发者来说,既然站在了巨...

    小柒2012
  • java面试必备之ThreadLocal

    按照传统的经验,如果某个对象是非线程安全的,在多线程环境下对象的访问需要采用synchronized进行同步。但是模板类并未采用线程同步机制,因为线程同步会降低...

    JKXQJ
  • SpringBoot开发案例之多任务并行+线程池处理

    前几篇文章着重介绍了后端服务数据库和多线程并行处理优化,并示例了改造前后的伪代码逻辑。当然了,优化是无止境的,前人栽树后人乘凉。作为我们开发者来说,既然站在了巨...

    小柒2012
  • 「每天一道面试题」ReentrantLock是如何实现公平锁及可重入的?

    A、B两个线程同时执行lock()方法获取锁,假设A先执行获取到锁,此时state值加1,如果线程A在继续执行的过程中又执行了lock()方法(根据持有锁的线程...

    JavaQ
  • 线程池之小结

    多线程:解决多任务同时执行的需求,合理使用CPU资源。多线程的运行是根据CPU切换完成,如何切换由CPU决定,因此多线程运行具有不确定性。

    蜻蜓队长

扫码关注云+社区

领取腾讯云代金券