线程安全性 --------------- 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) ; } } } } }