地图

谷歌地图坐标转百度地图坐标

可以在ditu.google.cn中取点,然后在http://www.gpsspg.com/maps.htm中输入坐标值,注意选择输入的经纬度是硬件/谷歌地球卫星,然后右侧可以百度等地图中看到对应的位置及转换后的坐标。

可以在postman中调用下面的接口转换坐标,调用时要加上Referer:http://www.gpsspg.com/iframe/maps/qq_181109.htm?mapi=2。

http://www.gpsspg.com/apis/maps/geo/?output=jsonp&lat=40.0137940000&lng=119.5019670000&type=1&callback=callback1&_=1564967351067

type:硬件/谷歌地球卫星坐标 0,谷歌坐标 1,百度坐标 2。

longitude 经度,值较大。
latitude 纬度,值较小。

http://www.gpsspg.com/latitude-and-longitude.htm

三种地球坐标系的区别

WGS-84:是国际标准,GPS坐标(Google Earth使用、或者GPS模块)
GCJ-02:中国坐标偏移标准,Google Map、高德、腾讯使用
BD-09:百度坐标偏移标准,Baidu Map使用
具体解释:

WGS84坐标系 即地球坐标系,国际上通用的坐标系。 设备一般包含GPS芯片或者北斗芯片获取的经纬度为WGS84地理坐标系。谷歌地图采用的是WGS84地理坐标系(中国范围除外,谷歌中国地图采用的是GCJ02地理坐标系。)

GCJ02坐标系 即火星坐标系,WGS84坐标系经加密后的坐标系。 出于国家安全考虑,国内所有导航电子地图必须使用国家测绘局制定的加密坐标系统,即将一个真实的经纬度坐标加密成一个不正确的经纬度坐标。

BD09坐标系 即百度坐标系,GCJ02坐标系经加密后的坐标系。搜狗坐标系、图吧坐标系等,估计也是在GCJ02基础上加密而成的。

Java事务

Spring声明式事务管理默认对非检查型异常进行事务回滚,而对检查型异常则不进行回滚操作。所以必须捕获检查型异常,捕获后再抛出非检查型异常,这样事务方才起效。

https://www.cnblogs.com/savorboard/p/distributed-system-transaction-consistency.html
//TODO

Java线程池

从JDK1.5开始,Java API提供了Executor框架,创建不同的线程池。有单线程池、数目固定的线程池、缓存线程池
Executors线程池工厂提供了一些创建不同特性线程池ThreadPoolExecutor的方法,它们都返回ExecutorService对象:

  • Executors.newSingleThreadPool()
  • Executors.newFixedThreadPool(int size):定长线程池,可控制线程最大并发数,超出的线程在队列中等待。
  • Executors.newCachedTheadPool():适合很多生存期短的任务,空闲线程会在指定时间内被回收。
  • Executors.newScheduledThreadPool():定长线程池,支持定时及周期性任务执行

它们内部都是封装了ThreadPoolExecutor:

ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 15, TimeUnit.SECONDS,new ArrayBlockingQueue(5), new ThreadPoolExecutor.CallerRunsPolicy());

线程池超载后的拒绝策略

池中的线程用光,等待队列也已排满。

扩展线程池

ThreadPoolExecutor提供了用于扩展的接口,比如要监控每个任务执行的开始和结束时间。

打印异常堆栈是排查问题的指南针,用线程池的execte()方法替换submit()方法,可以进而继承ThreadPoolExecutor来扩展出自己的TreaceThreadPoolExecutor。

Guava中扩展的线程池:

  • MoreExecutors.directExecutor() :将任务在调用线程中执行。
  • 将普通线程池转为Daemon线程池。
  • 对Future模式扩展。

估算线程池大小

threadsSize=cpu数量*cpu使用率*(1+等待时间/计算时间)

Fork/Join线程池

分而治之的思想,例如MapReduce,将大任务划分为小任务合成为最终结果。

ForkJoinPool线程池接受提交ForkJoinTask,ForkJoinTask对象可以调用fork()来分叉出小任务。

 

 

Java工具

jps:显示所有java进程

jstack:打印给定java进程的内部线程及堆栈

JMH:Java Microbenchmark Harness,Java微基准测试框架,是在OpenJDK中发布的用于性能测试框架。可以对方法的性能定量分析。

并发

基础概念

并发与并行:并发是串行交替执行,并行就是并行执行。并行只能出现在多核CPU情况下了。但它们的执行结果可能是一致的。并发概念独立于程序语言,多数语言都会涉及到并发问题。 临界区:多线程争用的共享数据。 死锁、饥饿、活锁:死锁是两方都争用;饥饿是一方争用而另一方谦让;活锁是两方都谦让。

并发级别

阻塞无饥饿:公平锁,不论线程优先级别,线程按照顺序排队。 无障碍:非阻塞调度是一种乐观的策略。都无障碍的执行,一旦检测到冲突,立即回滚。 无锁:保证必然有一个线程在有限步内完成。 无等待:要求所有线程都必须在有限步内完成。

锁机制

锁机制有两个层面:一种是代码层次上的,另外一种是数据库层次上的。锁同步更多指的是应用程序的层面,多个线程进来,只能一个一个的访问同一个数据。

数据库锁机制

  • 悲观锁(Pessimistic Locking):独占锁,在整个数据处理过程中,将数据处于锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制,也只有数据库层提供的锁机制才能真正保证数据访问的排他性。select * from account where name=”Erica” for update 这条 sql 语句锁定了 account 表中所有符合检索条件( name=”Erica” )的记录。

锁优化

  • 减小持有时间
  • 减小粒度:分割数据结构,适用于局部信息调用频繁,全局信息调用不频繁。
  • 锁粗化:把一组连续请求释放锁整合。
  • 读写分离锁:分割功能点,也是减小粒度的一种情况。
  • 锁分离:操作于结构上的位置不同,如take和put操作于LinkedBlockingQueue中链表的首尾。

JVM锁优化

  • 锁偏向:同一线程连续再次申请锁时,无须同步操作。适用于锁竞争少的场景。可以使用虚拟机参数开启锁偏向机制。
  • 轻量级锁:
  • 重量级锁:
  • 自旋锁:
  • 锁消除:通过逃逸分析,去除在没有竞争时使用的锁。可以使用虚拟机参数开启锁消除。

 

数据库基础

不同的数据库中字符串连接符不同:
1、oracle数据库中的连接符为||,例如连接字符串AB、CD可以使用“AB”||“CD”;
2、SQLSERVER 数据库连接符为+,例如连接字符串AB、CD可以使用“AB”+“CD”;
3、MYSQL数据库中连接符为+,例如连接字符串AB、CD可以使用“AB”+“CD”;

SQL聚集函数是以一个集合(集或者多重集)为输入,返回单个值的函数。SQL提供了五个聚集函数:

  • 平均值:avg
  • 最小值:min
  • 最大值:max
  • 总和:sum
  • 计数:count

而Having是一个过滤声明,是在查询返回结果集以后对查询结果进行的过滤操作,在Having中可以使用聚合函数。

范式

  • 第一范式(1NF)
    指数据库表的每一列数据项都不可分割,同一列中不能有多个值,即实体中的某个属性不能有多个值或者不能有重复的属性。简而言之,第一范式就是无重复的列。
  • 第二范式(2NF)
    要求数据库表中的每个实例或行必须可以被唯一地区分。要求实体的属性完全依赖于主关键字
    所谓完全依赖是指不能存在仅依赖主关键字一部分的属性,如果存在,那么这个属性和主关键字的这一部分应该分离出来形成一个新的实体,新实体与原实体之间是一对多的关系。简而言之,第二范式就是非主属性依赖于主关键字。
  • 第三范式(3NF)
    在满足第二范式的基础上,不存在传递函数依赖,那么就是第三范式。简而言之,第三范式就是属性不依赖于其它非主属性。

常用的关系数据库

  • Oracle
  • MySql
  • MariaDB
  • PostgreSQL

NoSQL

  • redis
  • mongodb
  • hbase
  • Cassandrs
  • pika

NewSQL

  • TiDB
  • OceanBase

数据库事务特性

  • A 原子性
  • C 一致性
  • I 隔离性
  • D 持久性

本地事务数据库断电的这种情况,它是怎么保证数据一致性的呢?使用SQL Server来举例,在执行事务的时候数据库首先会记录下这个事务的redo操作日志,然后才开始真正操作数据库,在操作之前首先会把日志文件写入磁盘,那么当突然断电的时候,即使操作没有完成,在重新启动数据库时候,数据库会根据当前数据的情况进行undo回滚或者是redo前滚,这样就保证了数据的强一致性。

Java枚举

在多数其它语言中,枚举只是命令整数常量的列表。在Java中,枚举实际上是类,枚举可以拥有成员变量、成员方法、构造方法。

enum Type{
    A,B,C,D;
}

枚举在编译后,会自动生成一个继承自java.lang.Enum的类。上面的枚举在编译后生成下面的代码:

class Type extends Enum{
    public static final Type A;
    public static final Type B;
    ...
}

更多参考 https://www.cnblogs.com/ldq2016/p/6627542.html

ordinal和value

ordinal()返回的值是索引,value()返回的是给枚举变量赋予的值。

public enum EnumDeviceType {
    Unknow(0),
    MasterSocket(1),
    SlaveSocket(2),
    DoorbellController(42),
    PowerControl(43);

    private int value = 0;

    private EnumDeviceType(int value) {
        this.value = value;
    }

    public int value() {
        return value;
    }
}

单例模式

单例模式有两种:“饿汉模式”和“懒汉模式”。直接使用饿汉模式,懒汉模式在任何情况下都不需要使用,因为饿汉模式先天就没有线程安全问题。

懒汉单例模式终极版

用volatile和synchronized配合双重检查锁(DCL:double check lock)机制,其中volatile用来保证多线程下的可见性:

  • 读volatile:每当子线程某一语句要用到volatile变量时,都会从主线程重新拷贝一份,这样就保证子线程的跟主线程的一致。
  • 写volatile: 每当子线程某一语句要写volatile变量时,都会在读完后同步到主线程去,这样就保证主线程的变量及时更新。

或者认为用volatile修饰singleton并不是用了volatile的可见性,而是用了java内存模型的“先行发生”(happens-before)原则的其中一条Volatile变量规则:对一个volatile变量的写操作先行发生于后面对这个变量的读操作,这里的“后面”指时间上的先后顺序。这样禁止指令重排序,确保singleton对象是在初始化完成后才能被读到。

public class Singleton {
private static volatile Singleton uniqueInstance;

private Singleton(){
}

public static Singleton getInstance(){
if(uniqueInstance == null){ //#1
synchronized(Singleton.class){ //#2
if(uniqueInstance == null){ //#3
uniqueInstance = new Singleton(); //#4
System.out.println(Thread.currentThread().getName() + ": uniqueInstance is initalized..."); //#5.1
} else {
System.out.println(Thread.currentThread().getName() + ": uniqueInstance is not null now..."); //#5.2
}
}
}
return uniqueInstance;
}
}

饿汉单例模式

以下两种写法在编译后等效

public class Singleton {
    private static final Singleton singleton=new Singleton();
    
    public static Singleton getInstance(){
        return singleton;
    }
}
public class Singleton {
    private static Singleton singleton;
    
    static{
        singleton=new Singleton();
    }
    
    public static Singleton getInstance(){
        return singleton;
    }
}

类的加载分为5个步骤:加载、验证、准备、解析、初始化,“饿汉模式”的创建对象是在类加载的初始化阶段进行的,jvm规范规定有且只有以下7种情况下会进行类加载的初始化阶段:

  • 使用new关键字实例化对象的时候
  • 设置或读取一个类的静态字段(被final修饰,已在编译器把结果放入常量池的静态字段除外)的时候
  • 调用一个类的静态方法的时候
  • 使用java.lang.reflect包的方法对类进行反射调用的时候
  • 初始化一个类的子类(会首先初始化父类)
  • 当虚拟机启动的时候,初始化包含main方法的主类
  • 当使用jdk1.7的动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解析结果REF_getStatic、REF_putStatic、REF_invokeStatic的方法句柄,并且这个方法句柄所对应的类没有进行过初始化,则需要先触发其初始化。

基本来说就是只有当以某种方式调用了这个类的时候,它才会进行初始化,而不是说jvm启动的时候就初始化。所以说假如单例类里只有一个getInstance()方法,那相当于当从其他类调用getInstance()方法的时候才会进行初始化,这和“懒汉模式”一样的效果。而jvm本身会确保类的初始化只执行一次。

当单例类里除了getInstance()方法还有一些其他静态方法,这样当调用其他静态方法的时候,也会提前初始化实例了。解决这个问题只要加个内部类就行了,这种模式叫holder pattern,如下,只有当调用getInstance()方法的时候,才会初始化内部类SingletonHolder:

public class Singleton {
    private static class SingletonHolder{
        private static final Singleton instance=new Singleton();
    }
    
    public static Singleton getInstance(){
        return SingletonHolder.instance;
    }
}

单元素enum来实现单例

public enum Singleton
{
    INSTANCE;

    public void dosomething()
    {
        System.out.println(this + " is speaking!");
    }
}