Skip to content

Commit fd5e9a4

Browse files
committed
feat: update articles
1 parent 44e1811 commit fd5e9a4

8 files changed

Lines changed: 148 additions & 24 deletions

File tree

‎Go/并发编程/README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
# 并发编程
22

3-
关于并发编程的通用基础内容,参阅[并发编程导论 https://url.wx-coder.cn/Yagu8 ](https://url.wx-coder.cn/Yagu8)。
3+
关于并发编程的通用基础内容,参阅 [Go 并发编程 https://url.wx-coder.cn/FO9EX ](https://url.wx-coder.cn/FO9EX)。

‎Go/并发编程/meta.json‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"permLink": "https://url.wx-coder.cn/Yagu8",
3+
"permDesc": "[Go 并发编程 https://url.wx-coder.cn/Yagu8 ](https://url.wx-coder.cn/Yagu8)"
4+
}

‎Java/并发编程/meta.json‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"permLink": "https://url.wx-coder.cn/72vCj",
3+
"permDesc": "[Java 并发编程 https://url.wx-coder.cn/72vCj ](https://url.wx-coder.cn/72vCj)"
4+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# 乐观锁 CAS
2+
3+
在 JDK1.5 中新增 `java.util.concurrent` (J.U.C)就是建立在 CAS 之上的。相对于对于 synchronized 这种阻塞算法,CAS 是非阻塞算法的一种常见实现。所以 J.U.C 在性能上有了很大的提升。我们以 `java.util.concurrent` 中的 `AtomicInteger` 为例,看一下在不使用锁的情况下是如何保证线程安全的。主要理解 `getAndIncrement` 方法,该方法的作用相当于 `++i` 操作。
4+
5+
```java
6+
public class AtomicInteger extends Number implements java.io.Serializable {
7+
8+
private volatile int value;
9+
10+
public final int get() {
11+
return value;
12+
}
13+
14+
public final int getAndIncrement() {
15+
for (;;) {
16+
int current = get();
17+
int next = current + 1;
18+
if (compareAndSet(current, next))
19+
return current;
20+
}
21+
}
22+
23+
public final boolean compareAndSet(int expect, int update) {
24+
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
25+
}
26+
}
27+
```
28+
29+
在没有锁的机制下需要字段 value 要借助 volatile 原语,保证线程间的数据是可见的。这样在获取变量的值的时候才能直接读取。然后来看看 `++i` 是怎么做到的。`getAndIncrement` 采用了 CAS 操作,每次从内存中读取数据然后将此数据和 `+1` 后的结果进行 CAS 操作,如果成功就返回结果,否则重试直到成功为止。而 `compareAndSet` 利用 JNI 来完成 CPU 指令的操作。
30+
31+
# 自旋锁
32+
33+
自旋锁是采用让当前线程不停地的在循环体内执行实现的,当循环的条件被其他线程改变时才能进入临界区。
34+
35+
```java
36+
public class SpinLock {
37+
38+
private AtomicReference<Thread> sign =new AtomicReference<>();
39+
40+
public void lock(){
41+
Thread current = Thread.currentThread();
42+
while(!sign .compareAndSet(null, current)){
43+
}
44+
}
45+
46+
public void unlock (){
47+
Thread current = Thread.currentThread();
48+
sign .compareAndSet(current, null);
49+
}
50+
}
51+
```
52+
53+
使用了 CAS 原子操作,lock 函数将 owner 设置为当前线程,并且预测原来的值为空。unlock 函数将 owner 设置为 null,并且预测值为当前线程。当有第二个线程调用 lock 操作时由于 owner 值不为空,导致循环一直被执行,直至第一个线程调用 unlock 函数将 owner 设置为 null,第二个线程才能进入临界区。由于自旋锁只是将当前线程不停地执行循环体,不进行线程状态的改变,所以响应速度更快。但当线程数不停增加时,性能下降明显,因为每个线程都需要执行,占用 CPU 时间。如果线程竞争不激烈,并且保持锁的时间段。适合使用自旋锁。

‎Java/并发编程/互斥与锁/自旋锁.md‎

Lines changed: 0 additions & 23 deletions
This file was deleted.
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Timer
2+
3+
Timer 计时器具备使任务延迟执行以及周期性执行的功能,但是 Timer 天生存在一些缺陷,所以从 JDK 1.5 开始就推荐使用 ScheduledThreadPoolExecutor(ScheduledExecutorService 实现类)作为其替代工具。
4+
5+
首先 Timer 对提交的任务调度是基于绝对时间而不是相对时间的,所以通过其提交的任务对系统时钟的改变是敏感的(譬如提交延迟任务后修改了系统时间会影响其执行);而 ScheduledThreadExecutor 只支持相对时间,对系统时间不敏感。
6+
7+
接着 Timer 的另一个问题是如果 TimerTask 抛出未检查异常则 Timer 将会产生无法预料的行为,因为 Timer 线程并不捕获异常,所以 TimerTask 抛出的未检查异常会使 Timer 线程终止,所以后续提交的任务得不到执行;而 ScheduledThreadPoolExecutor 不存在此问题。
8+
9+
所有的现代操作系统都通过进程和线程来支持并发。进程是通常彼此独立运行的程序的实例,比如,如果你启动了一个 Java 程序,操作系统产生一个新的进程,与其他程序一起并行执行。在这些进程的内部,我们使用线程并发执行代码,因此,我们可以最大限度的利用 CPU 可用的核心(core)。 Java 从 JDK1.0 开始执行线程。在开始一个新的线程之前,你必须指定由这个线程执行的代码,通常称为 task。这可以通过实现 Runnable——一个定义了一个无返回值无参数的 run()方法的函数接口,如下面的代码所示:
10+
11+
```java
12+
Runnable task = () -> {
13+
String threadName = Thread.currentThread().getName();
14+
System.out.println("Hello " + threadName);
15+
};
16+
17+
task.run();
18+
19+
Thread thread = new Thread(task);
20+
thread.start();
21+
22+
System.out.println("Done!");
23+
```
24+
25+
因为 Runnable 是一个函数接口,所以我们利用 lambda 表达式将当前的线程名打印到控制台。首先,在开始一个线程前我们在主线程中直接运行 runnable。 控制台输出的结果可能像下面这样:
26+
27+
```
28+
Hello main
29+
Hello Thread-0
30+
Done!
31+
```
32+
33+
或者这样:
34+
35+
```
36+
Hello main
37+
Done!
38+
Hello Thread-0
39+
```

‎Java/并发编程/线程协作/共享变量.md‎

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,46 @@
22

33
Java 编程语言允许线程访问共享变量,为了确保共享变量能被准确和一致的更新,线程应该确保通过排他锁单独获得这个变量。
44

5+
```java
6+
public class MySharedObject {
7+
8+
// static variable pointing to instance of MySharedObject
9+
public static final MySharedObject sharedInstance =
10+
new MySharedObject();
11+
12+
// member variables pointing to two objects on the heap
13+
public Integer object2 = new Integer(22);
14+
public Integer object4 = new Integer(44);
15+
16+
public long member1 = 12345;
17+
public long member1 = 67890;
18+
}
19+
20+
public class MyRunnable implements Runnable() {
21+
22+
public void run() {
23+
methodOne();
24+
}
25+
26+
public void methodOne() {
27+
int localVariable1 = 45;
28+
29+
MySharedObject localVariable2 =
30+
MySharedObject.sharedInstance;
31+
32+
//... do more with local variables.
33+
34+
methodTwo();
35+
}
36+
37+
public void methodTwo() {
38+
Integer localVariable1 = new Integer(99);
39+
40+
//... do more with local variable.
41+
}
42+
}
43+
```
44+
545
# volatile
646

747
Java 中的 volatile 关键字主要即是保证了变量的可见性,而不是原子性。JVM 中每一个变量都有一个主内存,为了保证最佳性能,JVM 允许线程从主内存拷贝一份私有拷贝,然后在线程读取变量的时候从主内存里面读,退出的时候,将修改的值同步到主内存。形象而言,对于变量 t,A 线程对 t 变量修改的值,对 B 线程是可见的。但是 A 获取到 t 的值加 1 之后,突然挂起了,B 获取到的值还是最新的值,volatile 能保证 B 能获取到的 t 是最新的值,因为 A 的 t+1 并没有写到主内存里面去。
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# ForkJoin
2+
3+
# 链接
4+
5+
- [concurrency-torture-testing-your-code-within-the-java-memory-model](http://zeroturnaround.com/rebellabs/concurrency-torture-testing-your-code-within-the-java-memory-model/)
6+
7+
- https://www.baeldung.com/java-fork-join

0 commit comments

Comments
 (0)