Java并发编程是指在Java程序中同时运行多个任务的能力。并发编程允许开发人员编写高效的程序,特别是在多核处理器和多处理器系统中。Java提供了丰富的API来处理并发编程,如线程(Thread)、同步(synchronization)、锁(Locks)、并发集合(java.util.concurrent Collections)、执行器(Executors)等。
以下是Java并发编程的一些核心概念和实践:
线程(Threads)
Java线程是程序中同时运行的两条或多条控制流程。线程可以通过继承Thread
类或实现Runnable
接口来创建。
// 通过继承Thread类
class MyThread extends Thread {
public void run() {
// 任务代码
}
}
// 通过实现Runnable接口
class MyRunnable implements Runnable {
public void run() {
// 任务代码
}
}
启动和管理线程
创建了线程或Runnable实例后,可以通过调用start()
方法来启动线程。
Thread t1 = new MyThread();
t1.start();
Thread t2 = new Thread(new MyRunnable());
t2.start();
同步(Synchronization)
在多线程环境中,同步是保证共享资源在多个线程之间正确使用的机制。Java提供了synchronized
关键字来实现方法或代码块级别的同步。
// 同步方法
public synchronized void syncMethod() {
// 访问共享资源的代码
}
// 同步代码块
public void syncBlock() {
synchronized(this) {
// 访问共享资源的代码
}
}
死锁(Deadlock)
当两个或多个线程永久地阻塞彼此等待获取锁时,就会发生死锁。避免死锁的方法包括避免嵌套锁、使用定时锁以及按顺序获取锁。
锁(Locks)
Java提供了显式锁机制,如ReentrantLock
,它提供了比synchronized
关键字更灵活的锁操作。
Lock lock = new ReentrantLock();
lock.lock();
try {
// 访问共享资源的代码
} finally {
lock.unlock();
}
并发集合(Concurrent Collections)
java.util.concurrent
包提供了线程安全的集合实现,如ConcurrentHashMap
、CopyOnWriteArrayList
等。
线程池(Thread Pools)
线程池是一种管理线程的方式,它允许你重用一组预先创建的线程来执行任务。Java的ExecutorService
接口及其实现类,如ThreadPoolExecutor
,提供了线程池功能。
ExecutorService executor = Executors.newFixedThreadPool(10);
executor.execute(new MyRunnable());
executor.shutdown();
Callable和Future
Callable
是类似于Runnable
的接口,但它可以返回一个结果,并且可以抛出异常。Future
可以保存异步计算的结果,并允许查询计算是否完成。
Callable<Integer> callable = new Callable<Integer>() {
public Integer call() {
return doSomeLongComputation();
}
};
ExecutorService executor = Executors.newFixedThreadPool(10);
Future<Integer> future = executor.submit(callable);
// 在未来某个时间获取结果
Integer result = future.get();
并发工具类
java.util.concurrent
包还提供了其他并发工具类,如CountDownLatch
、CyclicBarrier
、Semaphore
、Phaser
和Exchanger
,它们用于在多线程程序中协调线程间的合作。
Java内存模型(Java Memory Model)
Java内存模型定义了线程如何访问共享内存,以及变量如何被线程读写的规则。理解Java内存模型对于编写正确的并发程序至关重要。
并发编程是一个复杂的领域,涉及到许多需要注意的问题和高级特性。继续前面的讨论,这里将介绍更多的并发编程相关的高级概念和组件:
原子操作(Atomic Operations)
在Java中,java.util.concurrent.atomic
包提供了一组原子类,如AtomicInteger
、AtomicLong
、AtomicReference
等,它们使用高效的机器级指令(如CAS - Compare And Swap)来保证单个变量操作的原子性,无需使用synchronized
。
AtomicInteger atomicInt = new AtomicInteger(0);
int oldValue = atomicInt.get();
int newValue = oldValue + 1;
while (!atomicInt.compareAndSet(oldValue, newValue)) {
oldValue = atomicInt.get();
newValue = oldValue + 1;
}
并发工具类(Continued)
- CountDownLatch:允许一个或多个线程等待一组事件发生。
- CyclicBarrier:允许一组线程相互等待,直到所有线程都达到了公共屏障点。
- Semaphore:是一个计数信号量,用来控制同时访问特定资源的线程数量。
- Phaser:是一个更灵活的线程同步设备,类似于
CyclicBarrier
和CountDownLatch
的组合。 - Exchanger:允许两个线程在一个同步点交换对象。
并发队列(Concurrent Queues)
java.util.concurrent
包提供了几种并发队列的实现,如ConcurrentLinkedQueue
、LinkedBlockingQueue
、ArrayBlockingQueue
等,它们支持并发的插入和移除操作。
BlockingQueue<String> queue = new LinkedBlockingQueue<>();
// 生产者
queue.put("item");
// 消费者
String item = queue.take();
CompletableFuture
CompletableFuture
是在Java 8中引入的一个类,它提配合了Future的概念,并提供了丰富的API来合成、序列化、并行化、处理Future的完成事件等。
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
// 长时间的异步计算
// ...
return "result";
});
// 然后执行某些操作
future.thenAccept(result -> System.out.println("Result: " + result));
Fork/Join框架
Java 7引入了Fork/Join框架,这是一个用于并行执行任务的框架,基于“分而治之”的原则。它的核心是ForkJoinPool
类,它是ExecutorService
的一个实现。
public class MyRecursiveTask extends RecursiveTask<Integer> {
protected Integer compute() {
// 如果任务足够小,直接执行
if (/* 任务足够小 */ ) {
return computeDirectly();
} else {
// 任务过大,一分为二
MyRecursiveTask left = new MyRecursiveTask(/* 子任务 */);
MyRecursiveTask right = new MyRecursiveTask(/* 子任务 */);
// 执行子任务
left.fork();
right.fork();
// 等待子任务执行完,并得到其结果
int leftResult = left.join();
int rightResult = right.join();
// 合并子任务
return leftResult + rightResult;
}
}
}
ForkJoinPool pool = new ForkJoinPool();
Integer result = pool.invoke(new MyRecursiveTask());
并发编程的挑战
并发编程的主要挑战是如何正确地处理竞争条件、死锁、饥饿、活锁以及避免不一致性。正确地使用并发API和理解潜在的并发问题对于编写可靠和高效的并发应用程序至关重要。
标签:Java,Thread,编程,并发,线程,new,JAVA From: https://blog.csdn.net/guanglihuan/article/details/136853011