线程安全性
---------------
1、同步
同步代码块
同步方法
2、synchorize
java中任何对象都可以作为锁旗标。
对象内部维护了一个等待队列。
多线程编程时涉及到生产消费关系,可以借助队列来完成。
lock.wait()
lock.wait(int n) ;
lock.notify()
3、sleep和wait区别
sleep失去cpu抢占权,和锁定全无关。
wait()失去cpu抢占权,失去锁定全。
sync同步的缺点
----------------
成本较高,
Reente
100张票 2个人售票员
------------------
sync 18,826,327ns
lock 18,506,514ns
并发库下的ReentrantLock
------------------------
1.ReentrantLock
系统资源消耗较少。
ReentrantLock lock = new ReentrantLock() ;
//上锁
lock.lock();
//解锁
lock.unlock();
2.ReentrantReadWriteLock
可重入读写锁,具有更加细的粒度。
相当于乐观锁,支持一定程度的并发。
读锁也叫共享读锁(共享性的)。
写锁也就独占写锁(排他性的)。
线程1 线程2.读锁 | 线程2.写锁
-------------------------------------------------
readLock() | ok | not ok
-------------------------------------------------
writeLock() | not ok | not ok
ReentrantLock.lock()
------------------------
1、解释
如果其他线程没有持有该锁,请求锁定时会将计数器置为1。
如果当前已经持有锁,计数器+1并即刻返回。
如果被其他持有锁,当前线程不可用,处于休眠状态直到获得锁。
并将计数器归1。
ReentrantLock.tryLock()
------------------------
1、解释
尝试上锁,如果其他线程没上锁,上锁后立即返回,计数器归1,
如果线程已上锁,立刻返回false。
FairSync和NonfairSync
------------------------
公平性同步和不公平同步机制。
公平同步时排队机制,不公平机制是随机机制。
默认是不公平机制,和notify()方法的机制是类似的。
可重入锁内部通过同步对象实现的,而同步对象分为公平和不公平之分。
Unsafe对象使用CAS机制实现原子性
-----------------------
1、简介
compareAndSwap(),比较并交换.
i ++
i=1
long i = 1 ;//32
volatile
----------------------
1、简介
易变的,不稳定的,实时可见。
使用该关键字修饰的成员变量被线程修改后,立即被其他线程所见。
反之,其他线程有可能读到的仍然是修改之前的值。
AtomicInteger原子整数的操作
--------------------------
1、简介
该类内部封装了一个整数,通过底层unsafe类实现对该整数的操作符合原子性要求。
提供了很多相应的方法:
getAndIncrement() //int y = i ++ , 先赋值后加减
incrementAndGet() //int y = ++ i ,
getAndAdd(int x) //int y = i ++ x
并发库和sun底层库
-------------------------
ReentrantLock
ReentrantReadWriteLock
AtomicInteger
sun.misc.Unsafe
反射
--------------------------
1、Class
类类,是类的描述符,描述java类的属性的。
2、Method
class.declaredMethods() //声明的方法.
class.methods() //所有可见的方法。
3、Field
字段,成员变量。
Field f = class.getDeclaredFiild("name") ;
4、Constructor
构造函数,构造器,构造子。
//类的描述符
Class clazz1 = Cat.class ;
Constructor ctor1 = clazz1.getDeclaredConstructor(String.class) ;
//
ctor1.setAccessible(true);
Object obj = ctor1.newInstance("tom");
System.out.println(obj);
5、反序列化对象,不经过构造。
深度复制是通过java串行化技术实现。
java类需要实现java.io.Serializable接口,改接口没有任何方法,是标识性接口。
给jvm一个标记。使用transient修饰的成员变量不参与串行化过程,保持为null。
transient可以减少内存消耗,避免不要对象的构建,节省内存。
serialVersionUID串行ID主要用于反串过程,来完成类的版本比对的。
Cat cat = new Cat();
cat.setName("tom");
cat.setAge(12);
FileOutputStream fos = new FileOutputStream("d:/cat.dat") ;
ObjectOutputStream oos = new ObjectOutputStream(fos) ;
oos.writeObject(cat);
oos.close();
fos.close();
6、反串行是否经过构造函数
反串行化时不经过构造函数。因为没必要,串行化对象的是状态(成员变量),
串行化之后,状态是固定的,反串时只要恢复到对应状态即可,而构造函数是
创建对象的过程,最终目的也是在成员变量上设定值。
7.通过反射实现属性复制
/**
* 测试属性复制
*/
@Test
public void testPropertiesCopy() throws Exception {
Cat a = new Cat() ;
a.setName("tom");
a.setAge(12);
a.color = "red" ;
Cat b = new Cat();
copyProperties(a , b);
System.out.println();
}
private static void copyProperties(Object a , Object b){
try {
Class aClazz = a.getClass();
Class bClazz = b.getClass();
//得到a对象的所有字段
Field[] fs = aClazz.getDeclaredFields();
for(Field f : fs){
f.setAccessible(true);
Class ftype = f.getType(); //字段类型
String fname = f.getName() ; //字段名称
Object value = f.get(a) ; //字段值
try {
//得到b类中对应的字段
Field bf = bClazz.getDeclaredField(fname) ;
bf.setAccessible(true);
bf.set(b , value);
} catch (Exception e) {
continue;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
内省
-------------------
1、简介
专门用来操纵javabean的工具类,主要通过方法进行访问。
[属性]
getter/setter对应的名称部分。
getName()
[字段]
成员变量
2、实现属性复制
@Test
public void test1() throws Exception {
Cat a = new Cat();
a.setName("tom");
a.setAge(12);
a.setCategory("c1");
Cat b = new Cat() ;
copyProperties(a, b);
System.out.println();
}
/**
* 通过内省,操纵javabean,实现两个对象的属性复制。
*/
public static void copyProperties(Object a , Object b) throws Exception {
//获得类的javabean信息
BeanInfo abi = Introspector.getBeanInfo(a.getClass()) ;
//得到所有属性描述符
PropertyDescriptor[] apds = abi.getPropertyDescriptors();
//获得类的javabean信息
BeanInfo bbi = Introspector.getBeanInfo(b.getClass());
//得到所有属性描述符
PropertyDescriptor[] bpds = abi.getPropertyDescriptors();
//迭代
for(PropertyDescriptor pd : apds){
//得到属性名
String name = pd.getName() ;
Class apclazz=pd.getPropertyType() ;
//getter
Method getter = pd.getReadMethod();
if(getter != null){
getter.setAccessible(true);
for(PropertyDescriptor pd0 : bpds){
String bpname = pd0.getName();
Class bpclazz = pd0.getPropertyType();
Method bpsetter = pd0.getWriteMethod() ;
//ab两对象的属性名称和类型均相同
if(name.equals(bpname) && apclazz.equals(bpclazz) && bpsetter != null){
bpsetter.setAccessible(true);
Object value = getter.invoke(a) ;
bpsetter.invoke(b , value) ;
}
}
}
}
}