firewalld常用命令

添加开放的端口

1
firewall-cmd --permanent --add-port=5000/tcp

删除开放的端口

1
firewall-cmd --permanent --remove-port=5000/tcp

刷新

1
firewall-cmd --reload

查看

1
firewall-cmd --list-all

工作小记1

就上次的问题消息系统顺序问题,考虑到修改消息系统模块风险大,太多其他模块使用了该模块(由于系统技术债务,系统并没提供扩展写法,对该模块也没有足够的单元测试),最后没有就该思路走下去。
原来的业务问题是APP端有两次请求(一先一后),后台要求有顺序,否则可能执行不成功。至于为什么原系统是这样我就不知道了…两次请求会执行一些简单的逻辑,然后第二次请求会通过消息系统调用后面的服务,此时若第一次请求没有执行完,后面的服务就报错。
最后采取的方案是将操作2(包含参数)存入数据库,然后写定时任务再去调用,从而保证操作2在后面执行。
解决方案不优雅,但也算能解决当前的业务问题。重构好像要提上进程,希望能还些债务。

我的2016

始于一个微信电商项目的快速开发上线。
然后随公司一位老板换了个办公场所专心于一个项目。
7月去上海发展,公司是做Saas类型的企业服务,我也从在小公司要承担各种事务过渡到了只要专心开发,一下轻松了很多。
又经历了从开始的一个轻松的项目组被带到更要费心的另一个组。
工作技能方面也有了进一步的提升。
生活方面没什么值得说的,长进的怕是只有年龄。

设计模式总结

创建类模式

结构型模式

  • 适配器模式
  • 装饰器模式
  • 代理模式
  • 外观模式
  • 桥接模式
  • 组合模式
  • 享元模式

行为型模式

  • 模板方法模式
    模板方法模式
  • 策略模式
  • 观察者模式
  • 责任链模式
  • 迭代子模式
  • 命令模式
  • 备忘录模式
  • 状态模式
  • 访问者模式
  • 中介者模式
  • 解释器模式

其它

  • 并发型模式
  • 线程池模式

git fetch 与 git pull 区别

当远程主机版本库与本地版本库不一致时,可以使用git fetch将远程的更新取回到本地。
git fetch会取回所有分支更新,也可更新指定分支,如:

1
2
git fetch <远程主机名> <分支名>
git fetch origin develop

上面是取回远程develop分支。

其中 使用git remote可查看远程主机。

而git pull是取回远程分支再与本地分支合并。

1
2
$ git pull <远程主机名> <远程分支名>[:<本地分支名>]
$ git pull origin develop:branch1

上面是取回远程分支develop并且与本地branch1分支合并,若与当前分支合并则本地分支名部分可省略,如:

1
2
# 当前分支为branch1,则下面的写法和上面命令效果相同
$ git pull origin develop

git pull相当于是先git fetch再git merge,如:

1
2
$ git fetch origin
$ git merge origin/develop

若本地远程有单一追踪关系,还可省写为:

1
$ git pull

简单的说 git fetch仅将远程仓库的更新取回到本地仓库,不影响当前代码,而git pull除了取回外还会与workspace代码合并,影响当前代码。

单例模式常用写法

方法一:懒汉

在调用取得实例的方法时才会实例化对象

1
2
3
4
5
6
7
8
9
10
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}

方法二:饿汉

在单例类被加载时候完成实例化

1
2
3
4
5
6
7
public class Singleton {
private static final Singleton instance = new Singleton();
private Singleton (){}
public static Singleton getInstance() {
return instance;
}
}

方法三:双重校验锁定

懒汉升级版,JDK1.5后生效,毕竟getInstance上的synchronized多数情况都没有用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Singleton {
private volatile static Singleton singleton;
private Singleton (){}
public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}

方法四:枚举

1
2
3
4
5
public enum Singleton {
INSTANCE;
public void mothed() {
}
}

方法五:静态内部类

1
2
3
4
5
6
7
8
9
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}

消息系统顺序问题小计

今天就系统中的问题简单调研了一下消息系统顺序执行的解决方案。

环境

使用的消息系统是RabbitMQ。

问题

有两个操作操作1和操作2要放入消息系统,操作2要在操作1成功之后执行,否则操作2会异常。

这两个操作是前端一次用户操作里的两次请求,网上有很多说法如 将两条消息放入同一个队列、使用消息序列号SN等,但在不修改前端、两次请求到达后端的顺序不确定的情况下,不好实现。

解决

1、消费者收到操作2消息后先确认操作1的执行结果,符合条件再执行,否则将消息退回消息队列,可以延迟退回以防下次派发执行时操作1还未执行完成,同时未避免操作2可能的死循环,还可以设置重试次数,超过次数则放入死信队列或存储下来人工处理。

2、另外一种解决是先将操作2的内容存储起来,定时去尝试执行(可以临时解决问题但感觉不够通用,还需要专门去存储临时数据)。

Java List 排序(附中文排序)

1、Collections.sort的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 相关源码
package java.util;
...
public class Collections {
// 方法1
public static <T extends Comparable<? super T>> void sort(List<T> list) {
list.sort(null);
}
// 方法2
public static <T> void sort(List<T> list, Comparator<? super T> c) {
list.sort(c);
}
}

Collections.sort()方法可以对List的具体实现进行排序。

1
2
3
4
5
6
// 一个简单的例子
List<String> list = new ArrayList<>();
// list add data
Collections.sort(list); // 正序
Collections.sort(list, Collections.reverseOrder()); // 倒序

String实现了Comparable接口,因此我们可以调用 方法1 对由String组成的ArrayList进行排序。当然Java中还有很多实现Comparable接口的类,像Integer、Boolean、BigDecimal、File和Date等。

2、使用Comparable排序

1
2
3
4
5
6
7
// 相关源码
package java.lang;
import java.util.*;
public interface Comparable<T> {
public int compareTo(T o);
}

实现 Comparable接口的类需要重写compareTo()方法,该方法接收一个同类型的对象,要实现当前对象和接收到的对象的比较。compareTo()方法返回int类型的比较结果:

  • 正值表示当前对象比传递给compareTo()的对象大
  • 负值表示当前对象比传递给compareTo()的对象小
  • 零表示两个对象相等

待排序的对象X实现了Comparable接口,实现了compareTo方法后就可以使用 方法1 Collections.sort(list)进行排序了。

3、使用Comparator排序

1
2
3
4
5
6
7
8
9
// 相关源码
package java.util;
...
public interface Comparator<T> {
int compare(T o1, T o2);
}
...

Comparator接口提供了一个叫compare()的方法,要注意的是compare()接受两个相同类型的对象进行比较。
实现该接口实现该方法后,即可使用 方法2 Collections.sort(list, comparator)进行排序了。

最后附上一个字符串简体中文的排序。

1
2
3
List<String> names = new ArrayList<>();
// add data
Collections.sort(names, Collator.getInstance(Locale.SIMPLIFIED_CHINESE));

Java多线程-synchronized的使用

Java的同步主要是通过synchronized和Lock来实现。
本文主要说的是Java关键字synchronized的使用。

相关概念

  • 监视器
    在Java中每个对象都有一个锁标记(monitor),也称监视器,多线程同时访问某个对象时,线程只有获取了该对象的锁才能访问。

在Java中,可以使用关键字synchronized来标记一个方法或者代码块。

注意

synchronized可修饰方法、代码块,但不可去修饰属性、构造方法。

使用(同步方法与同步代码块)

方法同步

1
2
3
4
// 方法同步
public synchronized void test() {
// do something ...
}

synchronized用在方法上,则线程调用此方法时会获取该实例的对象锁,方法未结束之前其他线程只能等待。

同时其他线程也无法访问该实例的其他synchronized方法,因为一个对象只有一把锁,当一个线程获取了该对象的锁之后,其他线程就无法获取该对象锁。

同理,当一个线程访问该实例的synchronized方法时,其他线程能访问该对象的非synchronized方法,因为没使用到对象锁。

上面的前提是各线程调用的是同一对象实例,否则synchronized无效。

但若该synchronized方法为类方法,即方法修饰符为static,那么使用synchronized调用此方法的线程会获取该类的锁,只要该线程没有退出当前方法,其他线程也无法访问该方法。又若一个线程访问的是该对象的普通(非static)synchronized方法,另一个线程访问的是该对象(该类)的static synchronized方法,也不会发生互斥现象。因为它们一个获取的是对象锁,另一个是类锁,不冲突。

代码块同步

1
2
3
4
5
6
7
8
public void test2() {
...
// 代码块同步
synchronized(object) {
// do something ...
}
...
}

而用在代码块上,当线程运行到该代码块时,就会获得object对象的对象锁,如果多线程使用同一个object对象,那么此时就会同步,使得其他线程无法同时访问该代码块。使用synchronized代码块只对需要的部分进行同步,效率也更高。
当object为this时,代表获取的是当前实例的锁。即

1
2
3
4
5
6
7
8
9
10
11
12
public void test3() {
...
synchronized(this) {
// do something ...
}
...
}
// 此时,其效果等同于
public synchronized void test4() {
// do something ...
}

最后,使用synchronized出现异常时,JVM会自动释放当前线程占用的锁,因此不会由于异常导致出现死锁现象。

替换源解决Python pip安装慢的问题

问题

python官方源pip安装速度慢

解决

使用阿里云pip源替换官方源

新建编辑配置文件

1
vi ~/.config/pip/pip.conf

进行如下配置

1
2
3
4
[global]
timeout = 60
trusted-host = mirrors.aliyun.com
index-url = http://mirrors.aliyun.com/pypi/simple