本文共 5417 字,大约阅读时间需要 18 分钟。
线程在计算机编程中扮演着至关重要的角色。通过创建和管理线程,程序能够同时执行多项任务,提升效率。在本章中,我们将探索线程的基础机制,了解如何在Java中实现任务调度以及如何处理共享资源的竞争与死锁问题。
线程可以通过Runnable接口定义任务,实现run()方法即可。Runnable对象可以随时由Thread类或Executor服务运行。例如,LiftOff类通过实现Runnable接口,定义了一个倒计时任务:
class LiftOff implements Runnable { protected int countDown = 10; private static int taskCount = 0; private final int id = taskCount++; @Override public void run() { System.out.println("Thread:" + Thread.currentThread()); while (countDown > 0) { System.out.println(status()); } } private String status() { return "#" + id + "(" + countDown + ")" + " "; }} Thread类是Java中线程的核心,它通过构造器接受一个Runnable对象。调用start()方法启动线程运行,自动调用Runnable的run()方法。例如,使用BasicThreads类创建并启动线程:
class BasicThreads { public static void chapter21_2() { System.out.println("BasicThreads:" + Thread.currentThread()); Thread t = new Thread(new LiftOff()); t.start(); }} 在java.util.concurrent包中,Executor服务提供了更高级的线程管理功能。CachedThreadPool默认创建新的线程执行任务,与FternalThread和SingleThreadExecutor形成了不同策略的选择。
class CachedThreadPool { public static void chapter21_2() { System.out.println("CachedThreadPool:" + Thread.currentThread()); ExecutorService executorService = Executors.newCachedThreadPool(); for (int i = 0; i < 3; i++) { executorService.execute(new LiftOff()); } executorService.shutdown(); }} 若任务完成后需返回值,可以实现Callable接口。Callable支持异步计算,通过Future获取结果。
class CallableDemo { public static void chapter21_2() { ExecutorService executorService = Executors.newCachedThreadPool(); ArrayList > results = new ArrayList<>(); for (int i = 0; i < 3; i++) { results.add(executorService.submit(new TaskWithResult(i))); } for (Future fs : results) { try { System.out.println(fs.get()); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } } }} 在多线程环境下,共享资源可能引发竞争,导致逻辑错误。通过synchronize关键字实现方法同步,确保一种线程 一定在执行时占据资源。例如,SynchronizedEvenGenerator确保多个线程仅按顺序访问资源。
abstract class IntGenerator { public abstract int next();}class SynchronizedEvenGenerator extends IntGenerator { private int currentValue = 0; @Override public synchronized int next() { currentValue++; currentValue++; return currentValue; }} 线程间通过wait()与notify()方法进行等待与唤醒。wait()使线程挂起,直到notify()或notifyAll()被调用。例如,在WaxOMatic中,WaxOn和WaxOff任务通过condition实现等待与唤醒。
class WaxOMatic { public static void chapter21_5() { Car car = new Car(); ExecutorService executorService = Executors.newCachedThreadPool(); executorService.execute(new WaxOff(car)); executorService.execute(new WaxOn(car)); try { TimeUnit.MILLISECONDS.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } executorService.shutdownNow(); }} 正確解決哲學家問題,需调整拿取顺序。如FixedDiningPhilosophers,让最后一个哲学家先拿左筷子,解决死锁。
class FixedDiningPhilosophers { public static void chapter21_6() throws InterruptedException { int ponder = 3; int size = 2; ExecutorService executorService = Executors.newCachedThreadPool(); Chopstick[] chopsticks = new Chopstick[size]; for (int i = 0; i < size; i++) { Chopstick chopstick = new Chopstick(); Chopsticks[i] = chopstick; } for (int i = 0; i < size; i++) { Runnable run = () -> { try { while (!Thread.interrupted()) { right.take(); left.take(); } } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("philosopher " + i + " done"); }; executorService.execute(run); } TimeUnit.SECONDS.sleep(3); for (int i = 0; i < size; i++) { Chopstick left = Chopsticks[i]; Chopstick right = Chopsticks[(i + 1) % size]; left.drop(); right.drop(); } }} 通过比较Lock与Synchronized的性能差异,选择合适的互斥机制。同时,利用ConcurrentHashMap和CopyOnWriteArrayList等高效容器,确保线程安全与性能并存。
class ConcurrentHashMapExample { public static void chapter21_9() { ConcurrentHashMap map = new ConcurrentHashMap(); map.put("key1", 100); map.put("key2", 200); System.out.println(map.get("key1"));//100 System.out.println(map.size());//2 map Put "key3", 300 map remove"key1", 200 map.get("key1")//200 System.out.println(map.size())//3 }} 通过ActiveObjectDemo展示活动对象的特点,实现任务的串行化与资源管理。这种模式允许任务在多线程环境下无缝衔接,提升整体效率。
class ActiveObjectDemo { private ExecutorService executorService = Executors.newSingleThreadExecutor(); public Future calculateInt(int x, int y) { return executorService.submit(() -> { System.out.println("starting " + x + " + " + y); try { TimeUnit.MILLISECONDS.sleep(200); return x + y; } catch (InterruptedException e) { e.printStackTrace(); } }); } public void shutdown() { executorService.shutdown(); }} 通过以上方法和实例,可以全面理解线程机制,掌握解决多线程编程问题的关键策略。
转载地址:http://okdgz.baihongyu.com/