您当前的位置:首页 >  商业资讯  > 正文
今日视点:Java 多线程与并发编程·Java 工程师必知必会
来源:哔哩哔哩     时间:2023-05-18 06:57:47

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 多线程与并发编程的基础知识和常用技术。

在实际开发中,需要根据具体的场景选择合适的并发模型和工具,避免出现死锁、竞态条件等并发问题,从而实现高效、安全的多线程编程。

标签:

相关新闻

X 关闭

X 关闭

精彩推荐