Java 多线程的基本概念!
其他系列文章导航
Java基础合集
数据结构与算法合集
设计模式合集
多线程合集
分布式合集
ES合集
文章目录
其他系列文章导航
文章目录
前言
一、进程和线程
二、使用多线程的目的
三、线程安全
3.1 使用Atomic包下的类:
3.2 使用volatile关键字:
3.3 使用CountDownLatch:
3.4 使用ReentrantLock:
四、死锁解决
前言
在当今的计算机世界中,多线程编程已经成为了一种重要的技术,它能够充分利用多核处理器和多线程硬件的优点,提高程序的执行效率。Java作为一种流行的编程语言,也提供了丰富的多线程编程支持。
在Java中,多线程编程涉及到多个概念和机制,包括线程的创建、线程的状态、同步、并发和死锁等。这些概念和机制的学习和理解对于掌握Java多线程编程至关重要。
在接下来的文章中,我们将详细介绍Java多线程编程的基本概念和机制,并通过示例代码和案例分析帮助你更好地理解和掌握这些知识。
希望这些内容能够帮助你更好地理解和应用Java多线程编程技术,提高你的编程能力和效率。
一、进程和线程
进程:系统进行资源分配和调度的独立单位,每一个进程都有它自己的内存空间和系统资源。进程实现多处理机环境下的进程调度分派,切换时,都需要花费较大的时间和空间开销。
通俗话:为了提高系统的执行效率,减少处理机的空转时间和调度切换的时间,以及便于系统管理,所以有了线程,线程取代了进程了调度的基本功能。
简单来说,进程作为资源分配的基本单位,线程作为资源调度的基本单位。
编辑
二、使用多线程的目的
使用多线程最主要的原因是提高系统的资源利用率。
(现在CPU基本都是多核的,如果你只用单线程,那就是只用到了一个核心,其他的核心就相当于空闲在那里了)
比如说,我们系统Web服务器用的是Tomcat,Tomcat处理每一个请求都会从线程连接池里边用一个线程去处理。
又比如说,我们用连接数据库会用对应的连接池 Druid/C3PO/DBCP等等。
以下是一个简单的Java代码示例,演示了如何使用多线程来执行并发任务。
代码如下:
public class MultiThreadExample {
public static void main(String[] args) {
// 创建一个线程池
ExecutorService executor = Executors.newFixedThreadPool(10);
// 提交多个任务到线程池
for (int i = 0; i < 10; i++) {
executor.submit(() -> {
// 执行任务逻辑
System.out.println("Task " + Thread.currentThread().getId() + " is running.");
});
}
// 关闭线程池
executor.shutdown();
}
}
在这个示例中,我们创建了一个固定大小的线程池,并提交了10个任务到线程池中。每个任务都会输出当前线程的ID,表示它们正在并发地执行。通过使用多线程,我们可以充分利用系统的多核资源,提高应用程序的性能。
三、线程安全
我个人解决线程安全问题的思路有以下:
- 能不能保证操作的原子性,考虑atomic包下的类够不够我们使用。
- 能不能保证操作的可见性,考虑volatile关键字够不够我们使用
- 如果涉及到对线程的控制 (比如一次能使用多少个线程,当前线程触发的条件是否依赖其他线程的结果),考虑CountDownLatch/Semaphore等等
- 如果是集合,考虑iava.util.concurrent包下的集合类
- 如果synchronized无法满足,考虑lock包下的类
3.1 使用Atomic包下的类:
代码如下:
java`import java.util.concurrent.atomic.AtomicInteger;
public class AtomicCounter {
private AtomicInteger counter = new AtomicInteger(0);
public void increment() {
counter.incrementAndGet();
}
public int get() {
return counter.get();
}
}3.2 使用volatile关键字: 代码如下: java
public class SharedResource {
private volatile int value;
public void setValue(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}3.3 使用CountDownLatch: 代码如下: java
import java.util.concurrent.CountDownLatch;
public class ThreadController {
private CountDownLatch latch = new CountDownLatch(3); // 初始化为3个线程
public void startThread() {
new Thread(() -> {
try {
latch.await(); // 等待其他线程完成
System.out.println("All threads completed.");
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}`
3.4 使用ReentrantLock:
如果synchronized无法满足需求,可以考虑使用java.util.concurrent.locks包下的类,如ReentrantLock、ReentrantReadWriteLock等。这些锁类提供了更灵活的线程控制和同步机制。
代码如下:
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.Condition;
class MyResource {
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
private int count = 0;
public void increment() {
lock.lock();
try {
while (count == 5) {
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
count++;
System.out.println("Count is " + count);
condition.signalAll();
} finally {
lock.unlock();
}
}
}
四、死锁解决
原因: 当前线程拥有其他线程需要的资源,当前线程等待其他线程已拥有的资源,都不放弃自己拥有的资源。
避免死锁的方式一般有以下方案:
- 固定加锁的顺序,比如我们可以使用Hash值的大小来确定加锁的先后。
- 尽可能缩减加锁的范围,等到操作共享变量的时候才加锁。
- 使用可释放的定时锁。(一段时间申请不到锁的权限了,直接释放掉)
- 点赞
- 收藏
- 关注作者
评论(0)