应用开始启动正常,然后应用卡死。
ps -ef | grep java
进程还在,应用的 dubbo 端口还是活着的。
流程
查看应用 PID
ps -ef | grep java
应用开始启动正常,然后应用卡死。
ps -ef | grep java
进程还在,应用的 dubbo 端口还是活着的。
ps -ef | grep java
最近写一些任务调度相关的工具,总是涉及到线程池相关的处理。
一遍一遍的写,觉得非常浪费时间,而且没有凝聚成组件,无法优化和复用。
java 自带的线程池工具可以满足平时的需求,但是特性还是不够强大。
所以这并不是重复造轮子。
但是这又引入了第二个问题,如何充分的利用 jdk 自带的特性呢?
如果 jdk 升级了,特性我们可以享受到吗?
java.util.concurrent
是 java 为并发提供的强大的工具包。
本文将整理学习常见的类,API,适用场景,源码。
重点是类本身,并发和 jmm 将在其他系列学习。
Array是Java特有的数组。在你知道所要处理数据元素个数的情况下非常好用。java.util.Arrays 包含了许多处理数据的实用方法:
Arrays.asList:可以从 Array 转换成 List。可以作为其他集合类型构造器的参数。
Arrays.binarySearch:在一个已排序的或者其中一段中快速查找。
Arrays.copyOf:如果你想扩大数组容量又不想改变它的内容的时候可以使用这个方法。
Arrays.copyOfRange:可以复制整个数组或其中的一部分。
Arrays.deepEquals、Arrays.deepHashCode:Arrays.equals/hashCode的高级版本,支持子数组的操作。
Arrays.equals:如果你想要比较两个数组是否相等,应该调用这个方法而不是数组对象中的 equals方法(数组对象中没有重写equals()方法,所以这个方法之比较引用而不比较内容)。这个方法集合了Java 5的自动装箱和无参变量的特性,来实现将一个变量快速地传给 equals() 方法——所以这个方法在比较了对象的类型之后是直接传值进去比较的。
Arrays.fill:用一个给定的值填充整个数组或其中的一部分。
Arrays.hashCode:用来根据数组的内容计算其哈希值(数组对象的hashCode()不可用)。这个方法集合了Java 5的自动装箱和无参变量的特性,来实现将一个变量快速地传给 Arrays.hashcode方法——只是传值进去,不是对象。
Arrays.sort:对整个数组或者数组的一部分进行排序。也可以使用此方法用给定的比较器对对象数组进行排序。
Arrays.toString:打印数组的内容。
原子是世界上的最小单位,具有不可分割性。
比如 a=0;(a非long和double类型) 这个操作是不可分割的,那么我们说这个操作时原子操作。
再比如:a++; 这个操作实际是a = a + 1;是可分割的,所以他不是一个原子操作。非原子操作都会存在线程安全问题,需要我们使用同步技术(sychronized)来让它变成一个原子操作。一个操作是原子操作,那么我们称它具有原子性。
java的concurrent包下提供了一些原子类,我们可以通过阅读API来了解这些原子类的用法。
比如:AtomicInteger、AtomicLong、AtomicReference等。
可以原子性更新的引用值。
AtomicReference 和 AtomicInteger 比较类似。
都有 Unsafe 属性,和一个对应的值偏移量。
区别就是此处的 value 是通过 volatile
关键字修饰的变量。
public class AtomicReference implements java.io.Serializable {
private static final long serialVersionUID = -1848883965231344442L;
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset;
static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicReference.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
private volatile V value;
/**
* Creates a new AtomicReference with the given initial value.
*
* @param initialValue the initial value
*/
public AtomicReference(V initialValue) {
value = initialValue;
}
/**
* Creates a new AtomicReference with null initial value.
*/
public AtomicReference() {
}
}
可以原子性更新的 Integer 值,当然这个类并不能完全替代 Integer 对象。
使用起来还是很方便的。
比如说我们定义一个计数器,使用 AtomicInteger 可以同时兼顾性能与并发安全。
可以原子更新的 Long 值。
AtomicLong用于诸如原子递增的序列号之类的应用程序中,并且不能用作Long的替代品。
但是,此类确实扩展了Number,以允许通过处理基于数字的类的工具和实用程序进行统一访问。
LongAdder中会维护一个或多个变量,这些变量共同组成一个long型的“和”。当多个线程同时更新(特指“add”)值时,为了减少竞争,可能会动态地增加这组变量的数量。“sum”方法(等效于longValue方法)返回这组变量的“和”值。
当我们的场景是为了统计技术,而不是为了更细粒度的同步控制时,并且是在多线程更新的场景时,LongAdder类比AtomicLon g更好用。 在小并发的环境下,论更新的效率,两者都差不多。但是高并发的场景下,LongAdder有着明显更高的吞吐量,但是有着更高的空间复杂度。
在计算机数据存储中,数据条带化是分割逻辑顺序数据(例如文件)的技术,以便连续的段存储在不同的物理存储设备上。
当处理设备比单个存储设备提供数据更快地请求数据时,条带化非常有用。 通过在可以同时访问的多个设备上分布段,增加了总数据吞吐量。
它也是平衡磁盘阵列中I/O负载的有用方法。
条带化用于独立磁盘冗余阵列(RAID)存储中的磁盘驱动器,网络接口控制器,集群文件系统中的不同计算机和面向网格的存储,以及某些系统中的RAM。
JDK 8 的 java.util.concurrent.atomic 下有一个包本地的类 Striped64 ,它持有常见表示和机制用于类支持动态 striping 到 64bit 值上。
Unsafe类就和它的名字一样,是一个比较危险的类,它主要用于执行低级别、不安全的方法。
尽管这个类和所有的方法都是公开的(public),但是这个类的使用仍然受限,你无法在自己的java程序中直接使用该类,因为只有授信的代码才能获得该类的实例。
Unsafe API的大部分方法都是native实现,它由105个方法组成,主要包括以下几类:
(1)Info相关。主要返回某些低级别的内存信息:addressSize(), pageSize()
(2)Objects相关。主要提供Object和它的域操纵方法:allocateInstance(),objectFieldOffset()