Java 多线程与并发编程是 Java 工程师必须掌握的重要技能之一。随着计算机硬件性能的不断提升,多核 CPU 成为主流,开发高并发应用已成为越来越重要的需求。本文将介绍 Java 多线程与并发编程的基本概念和技术,包括线程、锁、同步机制、线程池、并发集合和并发编程的实践案例。
线程
(资料图片仅供参考)
线程是进程的一部分,是程序执行的最小单位。Java 中的线程是通过 Thread 类实现的。在 Java 中,线程有五个状态:新建状态、就绪状态、运行状态、阻塞状态和终止状态。通常使用 start 方法启动一个新线程,使用 join 方法等待线程执行完毕,使用 sleep 方法暂停线程的执行。以下是一个简单的线程实例:
public class MyThread extends Thread {
@Override
public void run() {
System.out.println("Hello from thread " + Thread.currentThread().getName());
}
public static void main(String[] args) {
MyThread thread1 = new MyThread();
MyThread thread2 = new MyThread();
thread1.start();
thread2.start();
}
}
锁和同步机制
在多线程编程中,需要使用锁和同步机制来保证线程安全。
Java 中提供了多种锁和同步机制,包括 synchronized 关键字、ReentrantLock 类、CountDownLatch 类、Semaphore 类等。
synchronized 关键字是 Java 中最常用的同步机制,可以用来保护临界区资源的访问,防止多个线程同时访问造成数据不一致的问题。以下是一个使用 synchronized 实现线程安全的计数器的例子:
public class Counter {
private int count;
public synchronized void increment() {
count++;
}
public synchronized int getCount() {
return count;
}
}
ReentrantLock 类是一个可重入锁,它提供了与 synchronized 关键字相似的同步功能,但更加灵活和可控。
以下是一个使用 ReentrantLock 实现线程安全的计数器的例子:
public class Counter {
private int count;
private ReentrantLock lock = new ReentrantLock();
public void increment() {
lock.lock();
try {
count++;
} finally {
lock.unlock();
}
}
public int getCount() {
lock.lock();
try {
return count;
} finally {
lock.unlock();
}
}
}
线程池
线程池是多线程编程中的一种常用技术,它可以管理和复用线程,提高程序的性能和可维护性。
Java 中提供了 Executor 框架和 ThreadPoolExecutor 类来实现线程池。以下是一个使用 ThreadPoolExecutor 实现的线程池例子:
public public class ThreadPoolExample {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(2);
for (int i = 0; i < 10; i++) {
executor.execute(new WorkerThread("Thread " + i));
}
executor.shutdown();
while (!executor.isTerminated()) {
// 等待线程池中的任务执行完毕
}
System.out.println("All threads have been terminated.");
}
}
class WorkerThread implements Runnable {
private String name;
public WorkerThread(String name) {
this.name = name;
}
@Override
public void run() {
System.out.println("Start executing thread " + name);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Finish executing thread " + name);
}
}
并发集合
Java 提供了一些并发集合类,例如 ConcurrentHashMap、ConcurrentLinkedQueue、CopyOnWriteArrayList 等,用于在多线程环境下安全地读写数据。这些集合类采用了一些特殊的技术,例如分段锁、CAS(Compare And Swap)等,来保证线程安全。
以下是一个使用 ConcurrentHashMap 实现的线程安全的计数器例子:
public class ConcurrentCounter {
private ConcurrentHashMap<String, Integer> counter = new ConcurrentHashMap<>();
public void increment(String key) {
counter.compute(key, (k, v) -> v == null ? 1 : v + 1);
}
public int getCount(String key) {
return counter.get(key);
}
}
并发编程实践
下面介绍一个简单的并发编程实践:多线程下载器。该下载器使用多个线程同时下载一个文件,从而加快下载速度。
public class MultiThreadDownloader {
private URL url;
private int threadCount;
public MultiThreadDownloader(String urlString, int threadCount) throws MalformedURLException {
this.url = new URL(urlString);
this.threadCount = threadCount;
}
public void download() throws IOException, InterruptedException {
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
int fileSize = connection.getContentLength();
connection.disconnect();
int blockSize = fileSize / threadCount + 1;
CountDownLatch latch = new CountDownLatch(threadCount);
for (int i = 0; i < threadCount; i++) {
int start = i * blockSize;
int end = Math.min((i + 1) * blockSize - 1, fileSize - 1);
new DownloadThread(url, start, end, latch).start();
}
latch.await();
System.out.println("Download completed.");
}
public static void main(String[] args) throws IOException, InterruptedException {
MultiThreadDownloader downloader = new MultiThreadDownloader("https://www.example.com/file.txt", 4);
downloader.download();
}
}
class DownloadThread extends Thread {
private URL url;
private int start;
private int end;
private CountDownLatch latch;
public DownloadThread(URL url, int start, int end, CountDownLatch latch) {
this.url = url;
this.start = start;
this.end = end;
this.latch = latch;
}
@Override
public void run() {
try {
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestProperty("Range", "bytes=" + start + "-" + end);
InputStream in = connection.getInputStream();
FileOutputStream out = new FileOutputStream("file.txt", true);
byte[] buffer = new byte[4096];
int len;
while ((len = in.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
in.close();
out.close();
connection.disconnect();
System.out.println("Downloaded bytes " + start + "-" + end + ".");
} catch (IOException e) {
e.printStackTrace();
} finally {
latch.countDown();
}
}
}
在主函数中,我们创建了一个 MultiThreadDownloader 对象,指定了下载文件的 URL 和线程数。
download 方法中,首先发送一个 HEAD 请求获取文件大小,然后根据线程数计算出每个线程下载的数据块大小。
接下来,使用 CountDownLatch 来控制所有线程的执行,创建 threadCount 个 DownloadThread 对象,并启动它们。
每个 DownloadThread 对象都指定了下载数据的起始位置和终止位置,以及一个 CountDownLatch 对象。
DownloadThread 的 run 方法中,首先发送一个 GET 请求,指定下载数据的范围,然后将数据写入本地文件,并计数器减一。最后在主函数中等待所有线程执行完毕。
总结
本文简单介绍了 Java 多线程与并发编程的基础知识和常用技术。
在实际开发中,需要根据具体的场景选择合适的并发模型和工具,避免出现死锁、竞态条件等并发问题,从而实现高效、安全的多线程编程。
标签:
据彭博社5月31日报道,万达集团计划以10亿元人民币(约合1 41亿美元)出售其数字支付牌照,正在与包括字节
当月要点:1、拿地总额同比下降8 4%,降幅近一步收窄2、城市选择高度集中,民营房企加速回归3、从各城市群
5月31日北向资金增持20 22万股招商港口。近5个交易日中,获北向资金减持的有2天,累计净减持2 08万股。近20
1、一般有以下几种帐户:基本户。2、企业必须开基本户,否则不能开其他银行帐户,基本户可以存取现金、划
1、Aninter-miningMingyueforyourviewing,weaveacoolautu
来为大家解答以下的问题,面石膏板防火等级耐火时间,纸面石膏板防火等级这个很多人还不知道,现在让我们一
5月31日,国家统计局服务业调查中心和中国物流与采购联合会公布的数据显示,5月制造业采购经理指数(PMI)
马斯克又来上海了。上证报记者获悉,5月31日晚间,特斯拉CEO埃隆& 183;马斯克(ElonMusk)按计划抵达上海。
直播吧5月31日讯据意大利记者罗马诺透露,吉达联合为本泽马开出接近1亿欧的年薪,皇马正等待球员做出决定。
新华社杭州5月31日电(记者顾小立)记者31日从浙江省经信厅获悉,浙江将加快推进5G全连接工厂建设,进一步
同一部智能手机对于有着不同需求的使用者来说,意义可能大不相同。职场人心目中的理想型智能手机,应该是在
1、建议你不要买长安车,长安车怠速不好治。2、水温高也不好治,另外长安车便宜。3、建议你买车之前也去看
1,云南有许多不知名但却非常美的小城,这需要你去发现,而不是只要提起云南就是大理丽江,烦死了。老实说
澳大利亚昆士兰大学MBA秋季学期,申请截止于每年5月31日左右。春季学期,申请截止于每年11月30日左右。需要
《乘风2023》成团夜时间曝光,复活赛时间已定,3位姐姐有望复活,陈冰,复活赛,汪小敏,许靖韵,李莎旻子,乘风2023
这个是没有准确答案的,要根据自己的实际需求和经济能力来决定。江城安心保和百万医疗险都是比较优秀的医疗
现代快报网是由凤凰出版传媒集团旗下的现代快报倾力打造的江苏新闻门户网站,目前在南京、苏州、无锡、常州
含饴弄孙,颐养天年,这是很多退休老人的选择。可在江西省南昌市进贤县前坊镇太平村西湖李家村,有四位退休
前不久,万州区钟鼓楼街道棉花地社区多个小区停车难问题得以化解,楼院停车有序了、出行也方便了、邻里更和
迈尔斯为勇士王朝的建立付出了巨大的努力迈尔斯的离职对于勇士队而迈尔斯则不同除了在体育行业最受追捧之外
X 关闭
X 关闭