java学习
JVM
多线程与高并发
23中设计模式
强大的Stream流
java NIO
♥JVM学习
三个阶段:
1、加载阶段
2、链接阶段(
验证:保证被加载类的正确性,文件格式检验、元数据检验、字节码检验(CA FE BA BE)、符号引用检验
准备:为类的变量分配内存且设置该变量的默认值,static修饰常量在编译时被分配了
解析:编译器自动收集类中所有变量的赋值和静态代码块中的语句生成<clinit>()方法并执行。一个类执<clint>方法时在多线程环境下要保证同步加锁
)
3、初始化过程
bootstrap:引导类加载器
ExtClassLoader:扩展类加载器
AppClassLoader:系统类加载器
双亲委派
AppClassLoader类的加载器是BootStrap, AppClassLoader的父类是BootStrap加载器。
jvm中启动参数
-Xms6G -Xmx6G:堆内存初始大小、最大大小
-XX:NewRatio=2 老年代与新生代比例,默认2
-XX:SurvivorRatio=8 :新生代中Eden与Survivor0、Survivor1的分配比例大小为8:1:1
♥多线程与高并发
进程:
线程:进程中最小的执行单元。
纤程:
线程状态:
synchronized关键字
♥当在方法上使用时锁为当前对象;当静态方法使用时锁为T.class,即类.class
public synchronized static void println(){ try { System.out.println("线程方法执行。。"); Thread.sleep(6000); } catch (InterruptedException e) { e.printStackTrace(); } }
♥可重入
当同个对象中synchronized m1()方法调用synchronized m2()方法时,允许执行不会产生死锁。当子类中同步方法调用父类中的同步方法时,此时锁的是当前对象,两者的为同一把锁。
♥异常跟锁
出现异常且未处理,锁将会释放,会造成乱入。
♥锁底层实现
偏向锁(当有竞争时升级为自旋锁)
自旋锁(自旋10次后升级为重量级锁)
重量级锁-OS
执行时间短且线程数少,用自旋;执行时间长且线程数多,用系统锁
♥volatile
保证线程可见性,禁止指令重排序(单例模式)
♥CAS操作(无锁优化、自旋)
AtomicInteger类似Atomic开头的类全是自旋锁。CAS(V,Expected,NewValue)V:当前值,Expected:期望值 ,NewValue:新的值;当前值和期望值相同时,认定为该值没有改变可以直接修改,否则将进行重试。
其中有Unsafe()类
ABA问题:加版本号
♥分段锁(LongAdder)
内部存在一个数组,将多个线程结果分布在数组中,最终将数组中的所有结果相加。
♥ReentrantLock和CountDownLatch
/**ReentrantLock * 与synchronized相比,ReentrantLock为CAS且功能强大 */ ReentrantLock lock = new ReentrantLock(true);//是否为公平锁 lock.isFair();//获取是否公平 try { lock.lock();//上锁 }finally { lock.unlock();//解锁 } boolean hasLock = lock.tryLock(2, TimeUnit.SECONDS);//等待2s内尝试拿到锁,不会产生死锁 /**CountDownLatch * 门栓,可以等待线程的结束 */ CountDownLatch latch = new CountDownLatch(100);//门栓 latch.countDown();//数量减1 latch.await();//等待在,在其他线程中数量减为0后等待结束
♥读写锁
//适用于频繁读操作,少量写操作。 ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); Lock readLock = lock.readLock(); Lock writeLock = lock.writeLock(); writeLock.lock();//保证仅有一个写操作 readLock.lock();//保证多个读操作同事执行,但是有写操作时禁止读操作
♥Semaphore,限流
//信号灯,Semaphore参数为可以允许最大的线程数。可以用来做限流 Semaphore semaphore = new Semaphore(1); new Thread(()->{ try { semaphore.acquire(); } catch (InterruptedException e) { e.printStackTrace(); }finally { semaphore.release(); } }).start(); }
♥线程之间数据通信Exchanger
Exchanger<String> srtingExchanger = new Exchanger<>(); new Thread(()->{ try { System.out.println("1:"+srtingExchanger.exchange("this is thread1")); } catch (Exception e) { e.printStackTrace(); }finally { } }).start(); new Thread(()->{ try { System.out.println("2:"+srtingExchanger.exchange("this is thread2")); } catch (Exception e) { e.printStackTrace(); } }).start();
注:该方法只允许2线程交换,但是可以有多个线程同时exchange,满足两个则交换,否则将会阻塞。
♥LockSupport
Thread t1 = new Thread(() -> { try { System.out.println("开始"); //阻塞线程,类似wait() LockSupport.park(); System.out.println("结束"); } catch (Exception e) { e.printStackTrace(); } }); t1.start(); Thread.sleep(10000); //继续线程,类似notify() LockSupport.unpark(t1);
♥23中设计模式
创建者模式:
创建者模式:
结构型模式:
行为性模式:
一、简单工厂模式
角色:工厂、接口、实现接口的具体类。
内容:通过工厂传入一个参数,返回不同的实例。
可以使用配置文件加载对应实例到容器中
1、配置文件beanName.properties:
myTest=bean.pojo
2、工厂类:
public class Factory {
//容器,存储初始化实例
private static HashMap<String, pojo> map = new HashMap<String, pojo>();
//加载配置文件,反射其对应实例
static {
Properties properties = new Properties();
InputStream beanName = Factory.class.getClassLoader().getResourceAsStream("beanName.properties");
try {
properties.load(beanName);
for (Object key : properties.keySet()) {
Class<?> aClass = Class.forName(properties.getProperty((String) key));
pojo pojo = (pojo) aClass.newInstance();
map.put((String) key, pojo);
}
} catch (Exception e) {
e.printStackTrace();
}
}
//从容器中获取对应的实例
public static pojo getTest(String classNmae) {
return map.get(classNmae);
}
}
3、客户端:
//从容器中获取对应的实例
public static pojo getTest(String classNmae) {
return map.get(classNmae);
}
二、工厂方法模式
角色:工厂接口、工厂实例、类接口、实现接口的具体类。
内容:客户通过传入不同的工厂,返回不同的实例。
三、抽象工厂模式
角色:工厂接口、工厂实例、抽象的类、具体的类
内容:客户调用不同的工厂,可以返回对应的类群。
浅克隆:实现Cloneable接口中的clone()方法,对非基本类型属性,仍指向原有属性所指向对象的内存地址
深克隆:
produce文件(省略setter,getter等等):
public class Produce {
private String a;
private String b;
private String c;
private String d;
}
方式一: 该方式分为 :产品Produce,建造者(抽象)Bulider,建造者(具体)Worker,♠指挥者 Director
注:由具体实现抽象,在具体中可以为produce中参数的赋值等操作,但是此时不调用不会赋值,只有通过指挥者的方法或者有参构造器进行对抽象方法的调用。
最后测试时为指挥者传入具体的建造者,并且调用获得produce
建造者(抽象):
public abstract class Builder {
public abstract void setAA();
public abstract void setBB();
public abstract void setCC();
public abstract void setDD();
public abstract Produce getPeoduct();
}
抽象者(具体):
public class Worker extends Builder {
//由具体建造者的无参构造方法new产品
private Produce p;
public Worker() {p=new Produce();}
@Override
public void setAA() {p.setA("注入A");}
@Override
public void setBB() {p.setB("注入b");}
@Override
public void setCC() { p.setC("注入c"); }
@Override
public void setDD() { p.setD("注入D"); }
@Override
public Produce getPeoduct() {return p;}
}
指挥者(可以合并到抽象类中):
public class Director {
public Produce getProduct(Builder builder){
builder.setAA();
builder.setBB();
builder.setCC();
builder.setDD();
return builder.getPeoduct();
}
}
测试:
Director director = new Director();
Produce p = director.getProduct(new Worker());
System.out.println(p.toString());
方式二:给方式将指挥者角色的功能赋予用户
建造者(抽象):
public abstract class Builder {
public abstract Builder setAA(String msg);
public abstract Builder setBB(String msg);
public abstract Builder setCC(String msg);
public abstract Builder setDD(String msg);
public abstract Produce getPeoduct();
}
抽象者(具体):依旧new对象,并且在这里对对象中属性赋值操作是返回的还是抽象者本身,最终要通过getProduct()方法实现获取对象
public class Worker extends Builder {
private Produce p;
public Worker() {p=new Produce();}
@Override
public Builder setAA(String msg) {p.setA(msg);return this;}
@Override
public Builder setBB(String msg) {p.setB(msg);return this;}
@Override
public Builder setCC(String msg) {p.setC(msg);return this;}
@Override
public Builder setDD(String msg) {p.setD(msg);return this;}
@Override
public demo2.Produce getPeoduct() {return p;}
}
测试:
Worker worker = new Worker();
Produce peoduct = worker.setAA("lala").setBB("hahah").getPeoduct();//通过链式编程实现对属性赋值
System.out.println(peoduct.toString());
♥代理模式
一、静态代理
真正执行的方法,被代理类的方法中调用,调用代理类方法则会调用真正的方法。
二、JDK动态代理(本质上是底层代码生成一个在内存中的类,去调用真正的方法)
//为了获取加载器和getInterfaces
pojo pojo = new pojo();
//本质是一个实现接口的类,该类代理的pojo中的所有方法
Peoper proxr = (Peoper) Proxy.newProxyInstance(pojo.getClass().getClassLoader(), pojo.getClass().getInterfaces(), new InvocationHandler() {
@Override
/**
* Object proxy:代理对象。
* Method method:调用对应方法的封装method对象
* Object[] args:调用方法的实际参数
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("增加对应的逻辑处理!");
Object invoke = method.invoke(pojo, args);
return invoke;
}
});
System.out.println("do返回:" + proxr.doing("do do do"));
proxr.reading("wgy", "java");
System.out.println("代理类Class:"+proxr.getClass());
使用arthas解析代理类Class:com.sun.proxy.$Proxy0,启动arthas-boot.jar后选择对应的进程,然后输入jad com.sun.proxy.$Proxy0
解析之后的真正代理类:
public final class $Proxy0 extends Proxy implements Peoper {
private static Method m4;
public $Proxy0(InvocationHandler invocationHandler) {
super(invocationHandler);
}
static {
m4 = Class.forName("bean.Peoper").getMethod("doing", Class.forName("java.lang.String"));
}
public final String doing(String string) {
try {
return (String)this.h.invoke(this, m4, new Object[]{string});
}
catch (Error | RuntimeException throwable) {
throw throwable;
}
catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
}
三、CGLIB动态代理
与JDK代理区别: CGLIB可以代理没有实现接口的类,而JDK代理则无法实现。
<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.3.0</version> </dependency>
//为了获取加载器和getInterfaces
pojo pojo = new pojo();
//创建Enhancer对象,类似JDK中的Proxy
Enhancer enhancer = new Enhancer();
//设置父类的字节码对象
enhancer.setSuperclass(pojo.class);
//设置回调函数
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("执行操作前");
Object invoke = method.invoke(pojo, objects);
System.out.println("执行操作后");
return invoke;
}
});
pojo pojoProxy = (pojo) enhancer.create();
System.out.println(pojoProxy.doing("wgy"));
一、类适配器:
实现适配者的接口,继承目标类。实现适配者中方法且在方法中调用父类方法。需要开发人员明确组件中接口。本质上就是在目标对象外套一层。
二、对象适配器:
与类适配器相比,只是不继承目标对象需要在外部传入一个目标对象。本质上就是在目标对象外套一层。
抽象装饰者继承抽象构建,在具体装饰者中传入旧具体构建对其装饰后返回新具体构建。
具体的特征:装饰者中会聚合一个父类,即Garnish中有FastFood。
类似单例模式,把多个重复的对象共享同一个。
♥桥接模式(多对多的情况下考虑使用)
桥梁模式的作用主要是将抽象和实现分离,抽象类与接口的实现分离,抽象的实体与实体的接口特性进行分离。
♥策略模式
示例代码:
优缺点:
该模式下包含角色:
1、抽象主题角色(Observable)
2、具体主题角色
3、观察者接口角色(Observer)
4、具体的观察者角色
具体代码:
1、主题角色(继承java类Observable)
public class MyObserverable extends Observable {
public void excute() {
//设置具体主题中发生变化
setChanged();
}
}
2、观察者角色(实现Observer接口,重写update()方法)
public class MyObserver implements Observer {
@Override
public void update(Observable o, Object arg) {
System.out.println("订阅通知收到消息!");
}
}
3、客户端
public class Client {
public static void main(String[] args) {
//创建具体主题。
MyObserverable myObserverable = new MyObserverable();
//创建观察者
MyObserver myObserver = new MyObserver();
//观察者订阅主题
myObserverable.addObserver(myObserver);
for (int i = 0; i < 5; i++) {
//在具体主题中设置主题发生变化。
myObserverable.excute();
//在具体主题中通知观察者,当主题发生变化时执行update()方法,若没有发生变化则不执行。
myObserverable.notifyObservers();
}
}
}
♥强大的Stream流
1、获取流
List<String> list = new ArrayList<>(); Stream<String> stream = list.stream(); //获取一个顺序流 Stream<String> parallelStream = list.parallelStream(); //获取一个并行流
注:顺序流是单线程运行,并行流为多线程执行;验证如下代码:
ArrayList<String> list = new ArrayList<>(); list.add("1,2,3,4,5,6"); list.add("a,b"); list.add("g,h,i,j,k,l"); list.add("p,k,s"); //顺序流 list.parallelStream().peek(o -> { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } }).forEach(a -> System.out.println(a)); //并行流 list.parallelStream().peek(o -> { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } }).forEach(a -> System.out.println(a));
2、中间操作
fliter
Stream<String> stringStream = list.stream().filter(a -> a.length() > 4);//只有长度大于4输出
limit
Stream<String> limit = list.stream().limit(6);//取前6个值
peek
list.stream().peek(o -> System.out.println(++o)).forEach(a -> System.out.println(a));//消费对其中的数据可以处理
skip:跳过n个值
sorted:排序
count:个数
reduce:规约
Integer integer = list.stream().reduce((a, b) -> { System.out.println(a + " " + b); return a + b; }).get();
map/flatMap
list.stream().map(a->a.replaceAll(",","")).forEach(a-> System.out.println(a));
list.stream().flatMap(a-> Arrays.stream(a.split(","))).forEach(a-> System.out.println(a));
3、Collectors工具库
toMap、toList、toSet:转对应集合
Map<Integer, String> collect = list.stream().collect(Collectors.toMap(a -> a.hashCode(), a -> a));
collect.forEach((a,b)-> System.out.println(a+":"+b));
groupingBy:分组
Map<Integer, List<String>> collect2 = list.parallelStream().collect(Collectors.groupingBy(a -> a.length()));
collect2.forEach((a,b)->{
System.out.println("wgy:"+a);
b.forEach(c-> System.out.println(c));
});
partitioningBy:分区,只能分为TRUE、FALSE
Map<Boolean, List<String>> collect3 = list.stream().collect(Collectors.partitioningBy(a -> a.length() > 5));
collect3.forEach((a, b) -> {
System.out.println("wgy:" + a);
b.forEach(c -> System.out.println(c));
});
mapping:映射
List<Integer> collect4 = list.stream().collect(Collectors.mapping(a -> a.length(), Collectors.toList()));
System.out.println(collect4);
joining:连接字符
reducing:规约
counting:计数
java NIO(同步非阻塞)
Bio 同步阻塞,面向流
Aio 异步非阻塞