java类的生命周期

加载

加载字节文件

连接

验证
验证类的合法性
字节码格式 语法等

准备
赋初值
常量赋值

解析
替换符号引用成内存地址

初始化

类被直接引用,生成类对象,执行静态代码

使用

直接引用 被动引用

卸载

单例模式

特征

在运行时阶段只能有一个对应类的实例对象

实现要点

  • 私有构造

似有构造控制对象的构建权利, 只赋给类本身

  • 对外的实例引用

单例的使用入口

饿汉式实现

要点: 静态属性, 直接在类初始化时实现

1
2
3
4
5
6
7
8
9
10
11
12
package com.luozi.designpatterns.singleton;

public class A {
private final static A INSTANCE = new A();

private A() {
}

public static A getInstance() {
return INSTANCE;
}
}

对象什么时候实例化呢, 类的生命周期中, 当类被直接引用的(一般是使用类的时候, 具体参照类的生命周期那片文章)时候, 会触发类的初始化, 这个时候就会依次执行类中的静态语句, 这里是创建单例

懒汉式实现

要点: 双重校验, 在获取单例时实例化; volatile 关键字保证值在线程间可见

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.luozi.designpatterns.singleton;

public class B {
// 加上volatile关键字, 保证属性的读在线程见可见
private static volatile B INSTANCE;

private B() {
}

public static B getInstance() {
if (INSTANCE == null) {
// 当 INSTANCE 为 null的时候, 使用锁, 保证只生成一个 实例
// 只在 INSTANCE 为null的时候使用锁, 而不是在方法上使用 锁, 提高效率
synchronized (B.class) {
// 在拿到索后, 还需要再次校验一下是否为 null, 因为可能好几个线程都走到拿到锁这一步了
// 要避免第二个及后面拿到锁的 线程重新生成对象, 同时这里使用 volatile 关键字, 保证值在线程中可见
if (INSTANCE == null) {
INSTANCE = new B();
}
}
}
return INSTANCE;
}
}

java泛型相关的问题

有一个方法, 需要传入所有类型的Number集合, 包括 List<Integer>, List<Double>, 设计一下方法签名

不能使用这种方法签名doSomething(List<Number> numbers) , 会报 doSomething(java.util.List<Number> numbers) can't applied to java.util.List<Integer>

使用以下两种方法签名都可以编译通过

1
2
doSomething(List<? extends Number> numbers)
doSomething(List numbers);

建议使用第一种, 这样对方法的参数没有做侵入, 让调用明确知道需要传入List<Number >

两个擦出后一样的方法签名编译能否成功, 比如 void do(List<Integer> numbers), void do(List<Double> numbers)

不会, 编译器会认为这两个方法签名一样, both method has same erasure

泛型赋值的问题

List<Integer> 是不能赋值给 List<Number>的, 但可以赋值给 List<? extends Number>, eg:

1
2
List<Integer> integers = new ArrayList<>();
List<? extends Number> numbers = integers;

java线程内通信与跨线程通信

threadLocal, 是线程内通信利器

新建一个threadLocal对象后, 当使用set的时候, 对象会以自身为key, 将set的值存入当前线程对象内的一个map中.

当在线程内想要使用该threadLocal set的值的时候, 直接get就可以拿到, 在jdk 1.5后, 通过threadLocal存放在线程中的 值, 会随着线程的销毁而慢慢被jvm回收掉.

但需要注意的是在springmvc这种框架中, 针对api请求使用了线程池技术, 在单个请求结束后, 线程本身不一定会销毁, 会在新的请求过来的时候重新启用, 针对这种情况, 如果针对每次请求共享数据, 必须在请求结束后remove掉通过 threadlocal set的值

  • demo, 带编写
  • 疑惑, springmvc的请求线程回收时机, 待处理

跨线程通信

在java 单进程中

  • 使用 wait notity notifyAll()

wait 和 notify 必须在 synchronized 代码块中, 且synchronized对象必须为同一个

不建议直接使用wait 和 notify , 建议使用java.util.concurrent包中的并发组件

实例demo, 待优化

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
87
88
89
90
package com.luozi.thread;

/**
* Created by luoziyihao on 6/20/17.
*/
public class CrossThreadCommunicationByWaitAndNotify {


public void start() {
Object lock = new Object();
boolean[] locked_1 = {false};

Runnable consumerRunner1 = getRunnable1(lock, locked_1);

final boolean[] locked_2 = new boolean[1];
Runnable consumerRunner2 = getRunnable2(lock, locked_2);

Thread thread1 = new Thread(consumerRunner1);
Thread thread2 = new Thread(consumerRunner2);

thread1.start();
thread2.start();

sleepForStart();

doNotify(lock, locked_1[0] && locked_2[0]);


}

private void doNotify(Object lock, boolean b) {
synchronized (lock) {
while (b) {

System.out.println("i am notify now");
lock.notifyAll();
break;
}
}
}

private void sleepForStart() {
try {
Thread.sleep(100L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

private Runnable getRunnable2(final Object lock, final boolean[] locked_2) {
return new Runnable() {
@Override
public void run() {
System.out.println("i am start for wait 2");
doWait(lock, locked_2);
System.out.println("i am wait ok , 2");

}
};
}

private Runnable getRunnable1(final Object lock, final boolean[] locked_1) {
return new Runnable() {
@Override
public void run() {
System.out.println("i am start for wait 1");
doWait(lock, locked_1);
System.out.println("i am wait ok, 1");


}
};
}

private void doWait(Object lock, boolean[] locked_1) {
synchronized (lock) {
try {
locked_1[0] = true;
lock.wait();
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
}
}

public static void main(String[] args) {
new CrossThreadCommunicationByWaitAndNotify().start();
}
}

  • 使用 condition, 类似的wait, notify, notifyall的效果

如果在代码中不使用 synchronized关键字, 而使用 Lock, 一般是 ReenTrantLock来做同步控制, 可以使用 lock.newCondition 来达到类似的wait, notify, notifyall的效果

对应的方法变成了 await(), signal(), signalAll()

  • 使用管道流
    pipedInputStream pipedOutputStream
    po.close(pi)

线程A 通过 输入流输入数据, 线程B 通过输出流读取数据

  • 并发队列
    ConcurrentLinkedQuene 非阻塞
    ArrayBlockingQuene LinkedBlockingQuene 阻塞 set满了 或者 poll空了会阻塞住
    ArrayBlockingQuene LinkedBlockingQuene 的区别 循环顺序表 和双向链表

如何愉快地安装node

建议用nvm管理node

1
2
3
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.0/install.sh | bash
nvm instal node
nvm use node

nvm每次将node安装到当前用户的home目录下, 所以启动用户务必和安装用户是同一个用户来规避权限问题

配置 .npmrc 使用淘宝镜像

1
registry=https://registry.npm.taobao.org/

配置常用的node工具

有时候系统找不到那些node应用的启动命令. 需要单独将这些命令放到 PATH

1
export PATH=${node's bin path}:$PATH 

curl命令的使用

POST请求传递表单参数

1
curl -X POST --data "name=tina&age=10" http://localhost/spring-hibernate-druid/user

指定host

1
curl -H"host" 

查看请求的详细信息

1
curl --location -v -l

跨服务器文件传输

在服务器间同步文件时, 用rsync命令比较快捷, 能够避免重复的传输, 删除多余的文件

1
rsync --delete -av --exclude './exclude_file' "${source_directory}"  ${user}@${server}:${desc_directory}

-- delete 表示删除目标目录存在, 原目录不存在的文件

-av 表示打印传输过程

--exclude 表示排除掉某些文件不做传输

"${source_directory}" 源文件目录. eg: /data/tmp/

${desc_directory} 目标服务器目录.

jenkins的自动构建

开启不安全的跨站点请求

title

title

给匿名用户权限

title

相关链接

拿到用户 token

title

或者全局读 + 读job

在项目页面填写用户token

title

脚本触发

1
curl  "http://localhost:8080/job/AYTools/build?token=1111111111111111111111" 

coding 触发

title