Java多线程编程是Java程序员必须要掌握的一项技能。在现代计算机中,CPU核心数量不断增加,多线程编程可以充分利用CPU资源,提高程序的执行效率。本文将从线程基础、线程同步、线程池、并发数据结构和Java8并发API等方面介绍Java多线程编程实践,并给出完整的代码示例。
一、线程基础
线程是操作系统最小的调度单位,它是进程的一个执行单元。Java线程可以通过继承Thread类或实现Runnable接口来创建。以下是一个继承Thread类的示例:
public class MyThread extends Thread { public void run() { // 线程执行方法 } } public class Test { public static void main(String[] args) { MyThread thread = new MyThread(); thread.start(); } }
以上代码创建了一个继承Thread类的MyThread类,并在main方法中启动了该线程。
除了继承Thread类创建线程外,还可以通过实现Runnable接口来创建线程,以下是一个实现Runnable接口的示例:
public class MyRunnable implements Runnable { public void run() { // 线程执行方法 } } public class Test { public static void main(String[] args) { MyRunnable runnable = new MyRunnable(); Thread thread = new Thread(runnable); thread.start(); } }
以上代码创建了一个实现Runnable接口的MyRunnable类,并在main方法中启动了该线程。
二、线程同步
Java多线程编程中,由于多个线程同时访问共享资源,容易出现线程安全问题。线程同步是解决线程安全问题的一种常用方法。
Java提供了多种线程同步机制,如synchronized关键字、Lock、Semaphore等。synchronized关键字是Java中最常用的线程同步机制,它可以修饰方法或代码块。
以下是一个使用synchronized关键字进行线程同步的示例:
public class MyRunnable implements Runnable { private int count = 0; public synchronized void increase() { count++; } public void run() { for (int i = 0; i < 1000000; i++) { increase(); } } public int getCount() { return count; } } public class Test { public static void main(String[] args) throws InterruptedException { MyRunnable runnable = new MyRunnable(); Thread thread1 = new Thread(runnable); Thread thread2 = new Thread(runnable); thread1.start(); thread2.start(); thread1.join(); thread2.join(); System.out.println(runnable.getCount()); } }
以上代码创建了一个使用synchronized关键字进行线程同步的MyRunnable类,并在main方法中启动了两个该线程,最终计算出count的值并输出。
三、线程池
Java中线程池是管理线程的一种机制,可以避免频繁创建和销毁线程的开销,提高程序的执行效率。
Java提供了ThreadPoolExecutor类实现线程池的功能。ThreadPoolExecutor类中的参数可以控制线程池中同时存在的线程数量、线程池中的线程空闲时间等。
以下是一个使用ThreadPoolExecutor类实现线程池的示例:
public class MyRunnable implements Runnable { private int count = 0; public synchronized void increase() { count++; } public void run() { for (int i = 0; i < 1000000; i++) { increase(); } } public int getCount() { return count; } } public class Test { public static void main(String[] args) throws InterruptedException { ExecutorService executorService = Executors.newFixedThreadPool(2); MyRunnable runnable = new MyRunnable(); for (int i = 0; i < 5; i++) { executorService.execute(runnable); } executorService.shutdown(); executorService.awaitTermination(1, TimeUnit.MINUTES); System.out.println(runnable.getCount()); } }
以上代码创建了一个使用ThreadPoolExecutor类实现线程池的MyRunnable类,并在main方法中启动了5个该线程,最终计算出count的值并输出。
四、并发数据结构
Java提供了多种并发数据结构,如ConcurrentHashMap、ConcurrentLinkedDeque等,它们可以在多线程环境中高效地操作共享资源。
ConcurrentHashMap是一个线程安全的哈希表,允许同时进行读写操作。以下是一个使用ConcurrentHashMap的示例:
public class MyRunnable implements Runnable { private Mapmap; private String key; public MyRunnable(Map map, String key) { this.map = map; this.key = key; } public void run() { for (int i = 0; i < 1000000; i++) { map.put(key, map.getOrDefault(key, 0) + 1); } } } public class Test { public static void main(String[] args) throws InterruptedException { Map map = new ConcurrentHashMap<>(); ExecutorService executorService = Executors.newFixedThreadPool(2); executorService.execute(new MyRunnable(map, "key1")); executorService.execute(new MyRunnable(map, "key2")); executorService.shutdown(); executorService.awaitTermination(1, TimeUnit.MINUTES); System.out.println(map); } }
以上代码创建了两个线程,对一个ConcurrentHashMap中的key进行100万次的递增操作,最终输出map的值。
五、Java8并发API
Java8增加了很多新的API来支持并发编程,如并行流、CompletableFuture等。
以下是一个使用并行流的示例:
public class Test { public static void main(String[] args) { Listlist = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); int sum = list.parallelStream().mapToInt(Integer::intValue).sum(); System.out.println(sum); } }
以上代码创建了一个List并使用parallelStream()方法将其转化为一个并行流,对流中的每个元素进行递增操作,并最终求和并输出。
除了并行流外,Java8也提供了CompletableFuture类来实现异步编程。以下是一个使用CompletableFuture的示例:
public class Test { public static void main(String[] args) throws ExecutionException, InterruptedException { CompletableFuturefuture = CompletableFuture.supplyAsync(() -> "Hello ") .thenApplyAsync(s -> s + "world") .thenApplyAsync(String::toUpperCase); System.out.println(future.get()); } }
以上代码使用CompletableFuture实现了一个异步执行的任务,并在每个异步任务完成后对其结果进行处理,最终输出处理后的结果。