Java编程 V 并发

线程

在java中,通过实现Runnable接口,可以实现多线程的创建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Thread_Test{
public static void main(String[] args) {
Runnable t1 = ()->{System.out.println(Thread.currentThread().getName());};
Runnable t2 = ()->{System.out.println(Thread.currentThread().getName());};
Thread s = new Thread(t1);
Thread m = new Thread(t2);
m.start();
s.start();
}
}
/*
* 输出
* Thread-1
* Thread-0
*/

竞态条件

当有多个线程需要共享对同一数据的存取,并且都调用了要对对象进行修改的方法,就会发生竞态条件。因为这些方法是非原子的 ,即 读-处理-存储 并非是同一个操作,这时就会导致读取的数据可能在多个线程间被处理,导致最终的结果不稳定。

通过定义锁结构,将一系列操作变为原子化操作,即在这一些列操作被完全执行前,其他线程无法对这个共享资源进行操作。

未加锁,非原子操作导致数据异常:

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

public class Thread_Test{
static int count = 0;
public static void main(String[] args) {

Runnable t1 = new Runnable() {
public void run() {
try {
int i = 0;
while (i < 100){
count++;
i++;
System.out.println("thread_name: "+ Thread.currentThread().getName() +"count : " + count);
Thread.sleep(10);
}
}catch (InterruptedException e) {
e.printStackTrace();
}
}
};
Runnable t2 = new Runnable() {
public void run() {
try {
int i= 0;
while ( i < 100){
count++;
i++;
System.out.println("thread_name: "+ Thread.currentThread().getName() +"count : " + count);
Thread.sleep(10);
}
}catch (InterruptedException e) {
e.printStackTrace();
}
}
};
Thread s = new Thread(t1);
Thread m = new Thread(t2);
m.start();
s.start();
}
}

对共享变量 count 加锁,程序正常运行

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

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Thread_Test{
static Lock lock = new ReentrantLock();
static int count = 0;
public static void main(String[] args) {

Runnable t1 = new Runnable() {
public void run() {
try {
int i = 0;
while (i < 100){
lock.lock();
count++;
lock.unlock();
i++;
System.out.println("thread_name: "+ Thread.currentThread().getName() +"count : " + count);
Thread.sleep(10);

}
}catch (InterruptedException e) {
e.printStackTrace();
}
}
};
Runnable t2 = new Runnable() {
public void run() {
try {
int i= 0;
while ( i < 100){
lock.lock();
count++;
lock.unlock();
i++;
System.out.println("thread_name: "+ Thread.currentThread().getName() +"count : " + count);
Thread.sleep(10);

}
}catch (InterruptedException e) {
e.printStackTrace();
}
}
};
Thread s = new Thread(t1);
Thread m = new Thread(t2);
m.start();
s.start();
}
}

synchronized 关键字

synchronized 关键字本身是用来声明一个对象作为整体是只可以被某个线程所“独占”的。

所以通过以下几种方法可以定义不同的控制块

类型 加锁对象 影响范围
synchronized实例方法 当前实例 (this) 同一个对象的同步方法互斥
synchronized静态方法 当前类的 Class对象 所有实例共享一把锁,互斥
synchronized (obj) 自定义锁对象 (obj) 只在使用这把锁的代码块互斥

通过synchronized 来声明一个方法是一个线程安全的方法

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

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Thread_Test{
static Lock lock = new ReentrantLock();
static int count = 0;
public static void main(String[] args) {
Runnable storer = new Runnable() {
@Override
public void run() {
try {
for(int i = 0; i < 100; i++){
operation(-5);
Thread.sleep(100);
}
} catch (Exception e) {
e.printStackTrace();
}

};
};
Runnable getter = new Runnable() {
@Override
public void run() {
try {
for(int i = 0; i < 100; i++){
operation(5);
Thread.sleep(100);
}
} catch (Exception e) {
e.printStackTrace();
}
}

};
;
Thread t1 = new Thread(storer);
Thread t2 = new Thread(getter);
t1.start();
t2.start();
}
synchronized static void operation(int money){
count = count + money;

System.out.println("current thread : " + Thread.currentThread().getName() + " , current count : " + count);
}
}

Object 的通知-等待

通过创建一个对象来,进行数据块的控制,
每个对象在JVM中有一个 监视器锁(Monitor) ,这是实现synchronized关键字背后的基础。

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
import java.util.ArrayList;
import java.util.List;

public class Thread_Test {
static final Object lock = new Object(); // 统一监视器锁
static List<Integer> array = new ArrayList<>(10);

public static void main(String[] args) {
Runnable producer = new Runnable() {
@Override
public void run() {
try {
for (int i = 0; i < 100; i++) {
synchronized (lock) {
while (array.size() == 10) {
lock.wait(); // 如果满了,等待
}
array.add(1); // 添加元素
array.add(1); // 添加元素
System.out.println("Producer added, size: " + array.size());
lock.notifyAll(); // 唤醒等待的线程
}
Thread.sleep(100); // 让出CPU
}
} catch (Exception e) {
e.printStackTrace();
}
}
};

Runnable consumer = new Runnable() {
@Override
public void run() {
try {
for (int i = 0; i < 100; i++) {
synchronized (lock) {
while (array.size() <= 0) {
lock.wait(); // 如果空了,等待
}
array.remove(0); // 移除元素
System.out.println("Consumer removed, size: " + array.size());
lock.notifyAll(); // 唤醒等待的线程
}
Thread.sleep(100);
}
} catch (Exception e) {
e.printStackTrace();
}
}
};

Thread t1 = new Thread(producer);
Thread t2 = new Thread(consumer);
t1.start();
t2.start();
}
}

所以 控制竞态条件的操作有两种

1.lock + condition

1
2
3
4
5
6
7
8
9
10
11
12
13
Lock lock = new ReentrantLock(); // 创建一把锁
Condition condition = lock.newCondition(); // 创建一把条件(跟这把锁绑定)
lock.lock(); // 加锁
try {
while (不满足条件) {
condition.await(); // 等待,并释放锁
}
// 满足条件后继续执行
// 处理逻辑...
condition.signalAll(); // 唤醒其他等待线程
} finally {
lock.unlock(); // 释放锁
}

2.synchronized + 对象块控制的等待,通知

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public Thread_Test() {
array = new ArrayList<>(10);
}

synchronized void store()throws InterruptedException{
while(this.array.size() >= 10){
wait();
}
array.add(1);
System.out.println(array.size());
notifyAll();
}
synchronized void remove()throws InterruptedException{
while (this.array.size() <= 0){
wait();
}
array.remove(0);
System.out.println(array.size());
notifyAll();
}

Callable

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
//
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

public class callable_test{
public static void main(String[] args) {
A a = new A();
Callable<Integer> callable = () -> { //实现Callable接口
for(int i =0 ;i < 100 ; i++){
a.num++;
}
return a.num;
};
var futuretask = new FutureTask<Integer>(callable); //将Callable传入 futuretask
new Thread(futuretask).start(); // 传入线程
try {
Integer num = futuretask.get(); // 从futuretask获取返回值
} catch (Exception e) {
e.printStackTrace();
}finally{
System.out.println(a.num);
}


}
}

class A {
int num = 1;
}

使用执行器

1
2
3
4
5
6
// newCachedThreadPool               创建一个线程池
// newFixedThreadPool 创建一个固定线程数的线程池
// newWorkStealingPool fork-join 任务的线程池
// newSingleThreadPool 只有一个线程的“池”,会顺序地执行提交的任务
// newScheduledThreadPool 用于调度执行的固定线程池
// newSingleThreadScheduledExecutor 用于调度执行的单线程“池”

向线程池提交线程

1
2
3
4
5
6
7
8
Future<T> submit(Callable<T> task)
Future<T> submit(Runable task)
Future<T> submit(Runable task ,T task)

var futuretask = new FutureTask<Integer>(callable);
ExecutorService executor = Executors.newCachedThreadPool();
executor.submit(futuretask);
executor.shutdown();

异步

异步本身是为了解决线程执行过程中 线程阻塞导致整体执行效率降低的问题。

在所有流程被串行执行时,流程中的任务等待响应阻塞后续任务的执行。

ComplateFuture

进程

java中创建进程

通过ProcessBuilder来进行进程创建。

java中的进程创建是向操作系统申请创建一个全新的进程,并不与

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
var builder = new ProcessBuilder("gcc","myapp.c")

builder = builder.directory(path.toFile());
// 改变工作目录
OutStream processln = p.getOutputStream(); // 接收标准输出
InputStream processOut = p.getInputStream(); // 接收标准输入
InputStream processError = p.getErrorStream(); // 接收标准错误

Process process = new ProcessBuilder("/bin/s","-l");
.directory(Path.of("/tmp").toFile())
.start();

try (var in = new Scanner(process.getInputStream())){
while (in.hasNextLine())
System.out.println(in.nextLine());
}

int result = process.waitFor(); // 等待进程执行结果
//或者
long delay = ... ;
if (process.waitfor(delay,TimeUnit.SECONDS)){
int result = process.exitValue();
...
}else {
process.destroyForcibly();
}

process.onExit().thenAccept(
p->System.out.println("Exit value : "+ p.exitValue()));


Java编程 V 并发
http://gadoid.io/2025/04/29/Java编程-V-并发/
作者
Codfish
发布于
2025年4月29日
许可协议