继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

Java高并发学习:从入门到实践指南

斯蒂芬大帝
关注TA
已关注
手记 230
粉丝 7
获赞 21
概述

Java高并发编程是现代软件开发中的关键技术,本文全面介绍了Java高并发学习的基础知识、线程管理、并发工具类以及实战案例,旨在帮助开发者理解和掌握Java高并发的核心概念和实践技巧。

Java高并发学习:从入门到实践指南
Java高并发基础知识

了解并发编程的重要性

在现代软件开发中,高性能和高并发已经成为软件系统的基本要求。并发编程可以充分利用多核处理器的能力,提高程序执行效率,满足用户对响应速度的需求。此外,通过并发编程可以实现更多复杂的功能和机制,例如并行计算、实时响应等。

Java并发编程的基本概念

Java并发编程涉及多个关键概念,包括线程、进程、并发模型等。线程是程序执行的基本单位,每个程序可以包含一个或多个线程。进程则是独立的执行环境,每个进程可以包含一个或多个线程。

并发模型和并行模型

Java并发编程主要关注的是并发模型。并发模型通过在不同线程之间分配执行时间来实现,而并行模型则通过将任务分配到不同的处理器核心上来实现。Java提供了多种并发工具和API,例如java.util.concurrent包,提供了丰富的并发编程支持。

下面是一些基本概念的代码示例:

public class BasicConcurrency {
    public static void main(String[] args) {
        // 创建线程
        Thread thread = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                System.out.println("Thread Running: " + i);
            }
        });

        // 启动线程
        thread.start();
    }
}
线程与多线程

Java线程的创建和启动

Java提供了多种创建和启动线程的方法。最常见的方式是继承Thread类或实现Runnable接口。

继承Thread类

public class MyThread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("Thread Running: " + i);
        }
    }

    public static void main(String[] args) {
        MyThread thread = new MyThread();
        thread.start();
    }
}

实现Runnable接口

public class MyRunnable implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("Runnable Running: " + i);
        }
    }

    public static void main(String[] args) {
        Thread thread = new Thread(new MyRunnable());
        thread.start();
    }
}

线程的状态和生命周期

Java线程主要有五种状态:新建可运行阻塞等待终止。其中,线程的生命周期中会经历这些状态变化。

  • 新建:线程被创建,但还没有调用start方法。
  • 可运行:线程调用start方法后,进入可运行状态。此时线程可以由线程调度器调度执行。
  • 阻塞:线程被阻塞,等待某些操作完成,例如I/O操作。
  • 等待:线程被阻塞,等待其他线程的唤醒操作。
  • 终止:线程执行完毕或异常退出。

线程同步与互斥

为了保证多个线程安全地访问共享资源,Java提供了多种同步机制。最常用的是synchronized关键字。

synchronized关键字用于确保同一时刻只有一个线程可以访问特定代码块或方法。

public class SynchronizedExample {
    private int count = 0;
    private final Object lock = new Object();

    public void increment() {
        synchronized (lock) {
            count++;
        }
    }

    public void decrement() {
        synchronized (lock) {
            count--;
        }
    }

    public int getCount() {
        return count;
    }

    public static void main(String[] args) {
        SynchronizedExample example = new SynchronizedExample();

        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                example.increment();
            }
        });

        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                example.decrement();
            }
        });

        t1.start();
        t2.start();

        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Final count: " + example.getCount());
    }
}
Java并发工具类

synchronized关键字

synchronized关键字可以用于方法或代码块,确保同一时刻只有一个线程可以访问该方法或代码块。

public class SynchronizedKeyword {
    private int count = 0;

    public synchronized void increment() {
        count++;
    }

    public synchronized void decrement() {
        count--;
    }

    public synchronized int getCount() {
        return count;
    }

    public static void main(String[] args) {
        SynchronizedKeyword sync = new SynchronizedKeyword();

        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                sync.increment();
            }
        });

        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                sync.decrement();
            }
        });

        t1.start();
        t2.start();

        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Final count: " + sync.getCount());
    }
}

volatile关键字

volatile关键字用于确保变量的可见性。当一个变量被标记为volatile时,任何线程对该变量的修改都会立即被其他线程看到。

public class VolatileExample {
    private volatile boolean ready = false;

    public void producer() {
        System.out.println("Producer is producing...");
        ready = true;
    }

    public void consumer() {
        while (!ready) {
            // 等待变量变化
        }
        System.out.println("Consumer is consuming...");
    }

    public static void main(String[] args) {
        VolatileExample ve = new VolatileExample();

        Thread t1 = new Thread(ve::producer);
        Thread t2 = new Thread(ve::consumer);

        t1.start();
        t2.start();
    }
}

Lock接口及其实现类

Lock接口提供了更灵活的锁机制,可以替代synchronized关键字。ReentrantLockLock接口的一个常见实现。

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ReentrantLockExample {
    private int count = 0;
    private final Lock lock = new ReentrantLock();

    public void increment() {
        lock.lock();
        try {
            count++;
        } finally {
            lock.unlock();
        }
    }

    public void decrement() {
        lock.lock();
        try {
            count--;
        } finally {
            lock.unlock();
        }
    }

    public int getCount() {
        return count;
    }

    public static void main(String[] args) {
        ReentrantLockExample rle = new ReentrantLockExample();

        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                rle.increment();
            }
        });

        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                rle.decrement();
            }
        });

        t1.start();
        t2.start();

        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Final count: " + rle.getCount());
    }
}

Condition接口及其实现类

Condition接口提供了比synchronized更细粒度的同步机制。ReentrantLocknewCondition方法可以创建一个Condition对象。

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ConditionExample {
    private final Lock lock = new ReentrantLock();
    private final Condition condition = lock.newCondition();
    private boolean ready = false;

    public void producer() {
        lock.lock();
        try {
            System.out.println("Producer is producing...");
            ready = true;
            condition.signal();
        } finally {
            lock.unlock();
        }
    }

    public void consumer() {
        lock.lock();
        try {
            while (!ready) {
                condition.await();
            }
            System.out.println("Consumer is consuming...");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        ConditionExample ce = new ConditionExample();

        Thread t1 = new Thread(ce::producer);
        Thread t2 = new Thread(ce::consumer);

        t1.start();
        t2.start();
    }
}
高并发场景下的数据结构

同步容器

Java提供了多种线程安全的集合类,例如VectorHashtableCollections.synchronizedList等。

import java.util.List;
import java.util.Vector;
import java.util.concurrent.CopyOnWriteArrayList;

public class SynchronizedContainers {
    private List<Integer> list = new Vector<>();

    public void add(int value) {
        synchronized (list) {
            list.add(value);
        }
    }

    public void addSafe(int value) {
        synchronized (list) {
            list.add(value);
        }
    }

    public static void main(String[] args) {
        SynchronizedContainers sync = new SynchronizedContainers();

        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                sync.add(i);
            }
        });

        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                sync.add(i);
            }
        });

        t1.start();
        t2.start();

        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("List size: " + sync.list.size());
    }
}

非阻塞数据结构

Java提供了多种非阻塞数据结构,例如ConcurrentHashMapConcurrentLinkedQueue等。这些数据结构使用CAS(Compare and Swap)操作实现线程安全性。

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;

public class NonBlockingContainers {
    private ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>();
    private ConcurrentLinkedQueue<Integer> queue = new ConcurrentLinkedQueue<>();

    public void put(String key, String value) {
        map.put(key, value);
    }

    public void add(int value) {
        queue.add(value);
    }

    public static void main(String[] args) {
        NonBlockingContainers nb = new NonBlockingContainers();

        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                nb.put("key" + i, "value" + i);
            }
        });

        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                nb.add(i);
            }
        });

        t1.start();
        t2.start();

        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Map size: " + nb.map.size());
        System.out.println("Queue size: " + nb.queue.size());
    }
}

基于AQS的锁设计模式

AbstractQueuedSynchronizer(AQS)是Java并发工具包中的一个基础类,用于构建自定义的同步机制。它可以实现复杂的数据结构,例如ReentrantLockSemaphore等。

import java.util.concurrent.locks.AbstractQueuedSynchronizer;

public class CustomLock extends AbstractQueuedSynchronizer {
    private boolean isLocked = false;

    protected boolean isHeldExclusively() {
        return isLocked;
    }

    public void lock() {
        acquire(1);
    }

    public void unlock() {
        release(1);
    }

    protected final boolean tryAcquire(int arg) {
        if (!isLocked) {
            isLocked = true;
            return true;
        }
        return false;
    }

    protected final boolean tryRelease(int arg) {
        if (isLocked) {
            isLocked = false;
            return true;
        }
        return false;
    }

    public static void main(String[] args) {
        CustomLock lock = new CustomLock();

        Thread t1 = new Thread(() -> {
            lock.lock();
            try {
                System.out.println("Locked by t1");
            } finally {
                lock.unlock();
            }
        });

        Thread t2 = new Thread(() -> {
            lock.lock();
            try {
                System.out.println("Locked by t2");
            } finally {
                lock.unlock();
            }
        });

        t1.start();
        t2.start();
    }
}
并发编程模式

生产者消费者模式

生产者消费者模式主要用于解决生产者和消费者之间的同步问题。生产者负责生产数据,消费者负责消费数据。

import java.util.concurrent.ArrayBlockingQueue;

public class ProducerConsumer {
    private final ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<>(10);

    public void producer(int value) {
        try {
            queue.put(value);
            System.out.println("Produced: " + value);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void consumer() {
        try {
            int value = queue.take();
            System.out.println("Consumed: " + value);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        ProducerConsumer pc = new ProducerConsumer();

        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                pc.producer(i);
            }
        });

        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                pc.consumer();
            }
        });

        t1.start();
        t2.start();
    }
}

读写器模式

读写器模式主要用于解决读写操作的同步问题。读操作可以并发执行,但写操作需要独占资源。

import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReaderWriter {
    private final ReadWriteLock lock = new ReentrantReadWriteLock();
    private final Lock readLock = lock.readLock();
    private final Lock writeLock = lock.writeLock();
    private int count = 0;

    public void read() {
        readLock.lock();
        try {
            System.out.println("Read: " + count);
        } finally {
            readLock.unlock();
        }
    }

    public void write(int value) {
        writeLock.lock();
        try {
            count = value;
            System.out.println("Write: " + value);
        } finally {
            writeLock.unlock();
        }
    }

    public static void main(String[] args) {
        ReaderWriter rw = new ReaderWriter();

        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                rw.read();
            }
        });

        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                rw.write(i);
            }
        });

        t1.start();
        t2.start();
    }
}

信号量与屏障

信号量用于实现有限资源的访问控制,屏障用于实现多线程的同步。

import java.util.concurrent.BoundedSemaphore;
import java.util.concurrent.CountDownLatch;

public class SemaphoreBarrier {
    private final BoundedSemaphore semaphore = new BoundedSemaphore(3);
    private final CountDownLatch barrier = new CountDownLatch(3);

    public void acquire() {
        try {
            semaphore.acquire();
            System.out.println("Acquired semaphore");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void release() {
        semaphore.release();
        System.out.println("Released semaphore");
        barrier.countDown();
    }

    public void await() {
        try {
            barrier.await();
            System.out.println("Barrier reached");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        SemaphoreBarrier sb = new SemaphoreBarrier();

        Thread t1 = new Thread(sb::acquire);
        Thread t2 = new Thread(sb::acquire);
        Thread t3 = new Thread(sb::acquire);
        Thread t4 = new Thread(sb::release);
        Thread t5 = new Thread(sb::release);
        Thread t6 = new Thread(sb::release);

        t1.start();
        t2.start();
        t3.start();
        t4.start();
        t5.start();
        t6.start();

        sb.await();
    }
}

资源池模式

资源池模式主要用于管理有限资源的分配和回收。典型的例子是数据库连接池。

import java.util.concurrent.ConcurrentLinkedQueue;

public class ResourcePool {
    private final ConcurrentLinkedQueue<Object> pool = new ConcurrentLinkedQueue<>();

    public void add(Object resource) {
        pool.add(resource);
    }

    public Object borrow() {
        return pool.poll();
    }

    public static void main(String[] args) {
        ResourcePool rp = new ResourcePool();

        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                rp.add(new Object());
            }
        });

        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                Object resource = rp.borrow();
                if (resource != null) {
                    System.out.println("Borrowed: " + resource);
                }
            }
        });

        t1.start();
        t2.start();
    }
}
实战案例

简单模拟高并发环境

模拟高并发环境可以使用JMeter或编写自定义的多线程代码。下面是一个简单的高并发环境模拟示例。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class HighConcurrencySimulation {
    private final int threads = 100;
    private final int iterations = 1000;

    public void simulate() {
        ExecutorService executor = Executors.newFixedThreadPool(threads);
        for (int i = 0; i < threads; i++) {
            executor.execute(() -> {
                for (int j = 0; j < iterations; j++) {
                    // 模拟并发操作
                    System.out.println("Thread: " + Thread.currentThread().getName() + ", Iteration: " + j);
                }
            });
        }
        executor.shutdown();
        try {
            executor.awaitTermination(1, TimeUnit.MINUTES);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        HighConcurrencySimulation hcs = new HighConcurrencySimulation();
        hcs.simulate();
    }
}

实战案例分析与优化

在实际应用中,需要对并发代码进行性能分析和优化。例如,可以使用JProfiler或VisualVM等工具进行性能分析,找出瓶颈并进行优化。

性能分析工具

  • JProfiler: 提供详细的CPU和内存分析,帮助找到性能瓶颈。
  • VisualVM: 集成了Java虚拟机监控工具,可以分析内存、线程等。

性能优化技巧

  • 减少锁的竞争:通过减少锁的范围或使用更细粒度的锁,减少锁的竞争。
  • 使用非阻塞数据结构:替换使用VectorHashtable等阻塞集合。
  • 减少同步开销:减少同步代码块的范围,减少不必要的同步操作。

性能调优技巧

性能调优是并发编程中非常重要的一部分。常见的优化技巧包括:

  • 减少锁的持有时间:锁的持有时间越长,竞争越激烈,性能越差。
  • 使用无锁数据结构:例如使用ConcurrentHashMap代替Hashtable
  • 减少线程切换开销:合理设置线程池大小,避免过多线程切换。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class PerformanceTuning {
    private final int threads = 20;
    private final int iterations = 100;

    public void simulate() {
        ExecutorService executor = Executors.newFixedThreadPool(threads);
        for (int i = 0; i < threads; i++) {
            executor.execute(() -> {
                for (int j = 0; j < iterations; j++) {
                    // 模拟高并发操作
                    System.out.println("Thread: " + Thread.currentThread().getName() + ", Iteration: " + j);
                }
            });
        }
        executor.shutdown();
        try {
            executor.awaitTermination(1, TimeUnit.MINUTES);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        PerformanceTuning pt = new PerformanceTuning();
        pt.simulate();
    }
}
总结

通过本文的学习,你已经掌握了Java高并发编程的基本概念和实践技巧。并发编程是一个广泛的领域,涉及到多线程、锁、同步、数据结构等多个方面。希望本文的内容可以帮助你在实际项目中更好地利用Java的并发编程能力,提高系统的性能和稳定性。

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP