分布式事务

分布式事务

  1. 主流的关系型数据库产品都是实现了XA接口,事务管理器和资源管理器之间使用XA协议,JTA(Java Transaction API)。
  2. TCC try comfirm cancel 。
  3. 本地消息表
    采用定时轮询扫描的方式,去检查消息表的数据。
  4. 消息队列
    采用时效性高的MQ,由对方订阅消息并监听,有消息时自动触发事件。
查看更多

JUC基本概念

1,tools(工具类):又叫信号量三组工具类,包含有

1)CountDownLatch(闭锁) 是一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待
2)CyclicBarrier(栅栏) 之所以叫barrier,是因为是一个同步辅助类,允许一组线程互相等待,直到到达某个公共屏障点 ,并且在释放等待线程后可以重用。
3)Semaphore(信号量) 是一个计数信号量,它的本质是一个“共享锁“。信号量维护了一个信号量许可集。线程可以通过调用 acquire()来获取信号量的许可;当信号量中有可用的许可时,线程能获取该许可;否则线程必须等待, 直到有可用的许可为止。 线程可以通过release()来释放它所持有的信号量许可。

2,executor(执行者):是Java里面线程池的顶级接口,但它只是一个执行线程的工具,真正的线程池接口是ExecutorService,里面包含的类有:

1)ScheduledExecutorService 解决那些需要任务重复执行的问题
2)ScheduledThreadPoolExecutor 周期性任务调度的类实现

3,atomic(原子性包):是JDK提供的一组原子操作类,

包含有AtomicBoolean、AtomicInteger、AtomicIntegerArray等原子变量类,他们的实现原理大多是持有它们各自的对应的类型变量value,而且被volatile关键字修饰了。这样来保证每次一个线程要使用它都会拿到最新的值。

4,locks(锁包):是JDK提供的锁机制,相比synchronized关键字来进行同步锁,功能更加强大,它为锁提供了一个框架,该框架允许更灵活地。包含的实现类有: 使用锁

1)ReentrantLock 它是独占锁,是指只能被独自占领,即同一个时间点只能被一个线程锁获取到的锁。
2)ReentrantReadWriteLock 它包括子类ReadLock和WriteLock。ReadLock是共享锁,而WriteLock是独占锁。
3)LockSupport 它具备阻塞线程和解除阻塞线程的功能,并且不会引发死锁。

5,collections(集合类):主要是提供线程安全的集合,

1)ArrayList对应的高并发类是CopyOnWriteArrayList,
2)HashSet对应的高并发类是 CopyOnWriteArraySet,
3)HashMap对应的高并发类是ConcurrentHashMap等等

查看更多

equal与hashcode 

一、equal 和 hashcode 作用和区别?

答:首先,我们要明白hashCode()和equals()方法的作用是什么,然后才能说他的区别,说了区别之后在说明使用的时候需要注意的地方,这样的回答思路基本是OK的。
一、hahsCode()和equals()的作用是什么?
hahsCode()和equals()的作用其实是一样的,目的都是为了比较两个对象是否相等一致
二、hahsCode()和equals()的区别是什么?
我们可以从两个角度分别介绍他们的区别:一个是性能,一个是可靠性。他们的主要区别体现在这里
1.equals()既然已经实现比较两个对象的功能了,为什么还需要hashCode()呢?
因为重写的equals()里一般比较的较为全面和复杂(它会对这个对象内所以成员变量一一进行比较),这样效率很低,而通过hashCode()对比,则只要生成一个hash值就能比较了,效率很高

二.那hashCode的效率这么高,为啥还要用equals()呢?

因为hashCode()并不是完全可靠,非常有可能的情况是,两个完全不同的对象的hash值却是一样的。
所以会有下面三个重要的结论:

  • equals()相等的两个对象他们的hashCode()肯定相等,即equals()绝对可靠。
  • hahsCode()相同的两个对象,它们的equals()不一定相同。即用hashCode()比较相同的时候不靠谱
查看更多

rocketmq主要概念

主要概念

1.NameServer
可以理解为是消息队列的协调者,Broker向它注册路由信息,同时Client向其获取路由信息,如果使用过Zookeeper,就比较容易理解了,但是功能比Zookeeper弱;
NameServer本身是没有状态的,并且多个NameServer直接并没有通信,可以横向扩展多台,Broker会和每一台NameServer建立长连接;

2.Broker
Broker是RocketMQ的核心,提供了消息的接收,存储,拉取等功能,一般都需要保证Broker的高可用,所以会配置Broker Slave,当Master挂掉之后,Consumer然后可以消费Slave;
Broker分为Master和Slave,一个Master可以对应多个Slave,Master与Slave的对应关系通过指定相同的BrokerName,不同的BrokerId来定义,BrokerId为0表示Master,非0表示Slave;

3.Producer
消息队列的生产者,需要与NameServer建立连接,从NameServer获取Topic路由信息,并向提供Topic服务的Broker Master建立连接;Producer无状态,看集群部署;

4.Consumer
消息队列的消费者,同样与NameServer建立连接,从NameServer获取Topic路由信息,并向提供Topic服务的Broker Master,Slave建立连接;

5.Topic和Message Queue
在介绍完以上4个角色以后,还需要重点介绍一下上面提到的Topic和Message Queue;字面意思就是主题,用来区分不同类型的消息,发送和接收消息前都需要先创建Topic,针对Topic来发送和接收消息,为了提高性能和吞吐量,引入了Message Queue,一个Topic可以设置一个或多个Message Queue,有点类似kafka的分区(Partition),这样消息就可以并行往各个Message Queue发送消息,消费者也可以并行的从多个Message Queue读取消息;

查看更多

jdk8时间互转和格式化

二 时间戳与LocalDateTime互转

2.1 LocalDateTime 转 时间戳

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
 //方式一
//这边值得一提的是在中国的时区偏移是8小时,本次示例转的时间戳是秒级别,得到的值是一个long值;知识追寻者这边是当前时间,故读者得到的结果与知识追寻者得到的结果不一致;读者可以使用站长工具进行测试校验
// https://unixtime.51240.com/
@Test
public void localTimeTest1(){
// 获得当前时间
LocalDateTime localDateTime = LocalDateTime.now();
// 将当前时间转为时间戳
long second = localDateTime.toEpochSecond(ZoneOffset.ofHours(8));
// 1580706475
System.out.println(second);

}

//方式二
// 此方法执行的结果与之前一致,也是秒级别
@Test
public void localTimeTest2(){
// 获得当前时间
LocalDateTime localDateTime = LocalDateTime.now();
// 将当前时间转为时间戳
long second = localDateTime.toInstant(ZoneOffset.ofHours(8)).getEpochSecond();
// 1580707001
System.out.println(second);

}

// 方式三
// 此方式转的将是毫秒级别,直接用于站长工具是测试不出来,读者应该将其除1000取商获得正确的秒级时间戳;
public void localTimeTest3(){
// 获得当前时间
LocalDateTime localDateTime = LocalDateTime.now();
// 将当前时间转为时间戳
long milliseconds =localDateTime.toInstant(ZoneOffset.ofHours(8)).toEpochMilli();
// 1580707268
System.out.println(milliseconds/1000);
}

2.2 时间戳 转LocalDateTime
以下几种获取的LocalDateTime方式按读者需求进行获取,不同的精确值,将获取不同的结果;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

// 方式一
// 先获取时间戳为秒级别,然后通过转换为LocalDateTime
public void localTimeTest4(){
//获得时间戳
long second = LocalDateTime.now().toInstant(ZoneOffset.of("+8")).getEpochSecond();
// 将时间戳转为当前时间
LocalDateTime localDateTime = LocalDateTime.ofEpochSecond(second, 0, ZoneOffset.ofHours(8));
// 2020-02-03T13:30:44
System.out.println(localDateTime);
}


//方式二
//本次获取的时间搓将是毫秒级别故要除以1000

public void localTimeTest5(){
//获得时间戳
long milliseconds = LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli();
// 将时间戳转为当前时间
LocalDateTime localDateTime = LocalDateTime.ofEpochSecond(milliseconds/1000, 0, ZoneOffset.ofHours(8));
// 2020-02-03T13:35:53
System.out.println(localDateTime);

}

//方式三
//本方式精确值是毫秒级别,故得到的结果会存在三位小数点;

@Test
public void localTimeTest6(){
//获得时间戳
long milliseconds = LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli();
// 将时间戳转为当前时间
LocalDateTime localDateTime = Instant.ofEpochMilli(milliseconds).atZone(ZoneOffset.ofHours(8)).toLocalDateTime();
// 2020-02-03T13:38:35.799
System.out.println(localDateTime);

}

查看更多

jdk8-date和timeAPI

一 我们为什么要学习 java.timeAPI

原先的Date and Calendar 类的api比较复杂,不易于理解,应用起来不是很灵活。
Calendar 是个线程不安全的类会导致SimpleDateFormat线程不安全。
java.time是JSR 310: Date and Time API.规范所开发,其所有类都是线程安全的或者是枚举类型的类
java.time 的API 使用简单,能够灵活计算时间,矫正时间。

二 LocalDate

LocalDate 是 日期,在java.time 中 日期和时间是可以分开和组合的。

2.1 创建date的方式
// 创建date的方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public void LocalDateTest(){
// 1当前日期 常用
LocalDate now = LocalDate.now();
System.out.println(now);//2019-10-27
// 2指定年月 日 方式 常用
LocalDate ofDate = LocalDate.of(2018, 8, 8);
System.out.println(ofDate);//2018-08-08
// 3使用Clock方式创建 不常用
Clock clock = Clock.systemDefaultZone();
LocalDate date = LocalDate.now(clock);
System.out.println(date);// 2019-10-27
// 4 指定年份 和 一年的天数进行创建
LocalDate localDate = LocalDate.ofYearDay(2018, 256);
System.out.println(localDate);// 2018-09-13

}

2.2 使用LocalDate读取date

查看更多

jdk8-stream

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
List<People> list = new ArrayList<>();

//取前20个
list=list.stream().limit(20).collect(Collectors.toList());


//取属性
List<String> spuCodes = list.stream().map(People::getName).collect(Collectors.toList());

//拼接
List<Integer> numbers = ImmutableList.of(1, 2, 3, 4, 5);
String result = numbers.stream().map(Object::toString).collect(Collectors.joining(","));
String result = numbers.stream().collect(Collectors.joining(", ", "[", "]"));


//根据age对list分组 List<X> -> map<x.id,List<x>>
Map<String,List<People>> groupByAge = list.stream().collect(Collectors.groupingBy(People::getAge));

//根据age对list的属性分组 List<X> -> map<x.id,List<x.name>>

Map<Long,List<String>> exhibitionPitemMap = list.stream().collect(
Collectors.groupingBy(People::getLong, Collectors.mapping(People::getName, Collectors.toList())));


//根据age进行排序(reserve倒序)
List<People> peopleListSorted = list.stream().sorted(Comparator.comparing(People::getAge)
.reversed()).collect(Collectors.toList());


//提取age,并排序
List<String> ageList = list.stream().map(People::getAge).distinct().sorted().collect(Collectors.toList());



//提取年龄大于20的people
List<People> olderThan20 = list.stream().filter(e->Integer.parseInt(e.getAge()) > 20)
.collect(Collectors.toList());

//累加
BigDecimal totalMoney = list.stream().map(People::getMoney).reduce(BigDecimal.ZERO, BigDecimal::add);

list.stream().mapToLong(People::getAge).sum();


Long sum2 = list.stream().reduce(0L, Long::sum);


//过滤取单个值
People people = list.stream().filter(e->e.getAge().equals("20")).findFirst().orElse(null);



//查找流中最大值和最小值
List<Person> personList = generatePersonList();
Person olderOne = personList.stream().max(Comparator.comparing(Person::getAge)).orElse(null);
Person youngerOne = personList.stream().min(Comparator.comparing(Person::getAge)).orElse(null);

//对象去重
ArrayList<Person> collect = personList.stream().collect(Collectors.collectingAndThen(
Collectors.toCollection(() -> new TreeSet<>(Comparator.comparingInt(Person::getAge))),
ArrayList::new));


//转换成String[]
list..stream().toArray(String[]::new)


//拼接字符串
request.getModuleIdList().stream().map(x-> x.toString()).collect(Collectors.joining(","));


// List<x> -> Map<x.id,x>

//1,key存在重复时,会抛出异常
Map<Long, Person> id2Entity = personList.stream().collect(Collectors.toMap(Person::getId, x-> x));

//2,解决key重复异常情况
Map<Long, Person> entityMap= personList.stream().collect(Collectors.toMap(Person::getId, Function.identity(),(x,y) -> y));



//list 分割
int pageNum = (list.size()+ PAGE_SIZE -1) / PAGE_SIZE;
List<List<Long>> splitList = Stream.iterate(0, n->n+1).limit(pageNum).parallel()
.map(a-> list.stream().skip(a*PAGE_SIZE).limit(PAGE_SIZE).parallel().collect(Collectors.toList())).collect(Collectors.toList());

查看更多