线程安全:
确保共享资源的正确访问和修改,避免并发冲突。可以通过同步机制(如锁、互斥量、信号量等)或使用线程安全的数据结构来实现线程安全。
案例:银行账户并发访问
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class BankAccount {
private int balance;
private Lock lock = new ReentrantLock();
public void deposit(int amount) {
lock.lock();
try {
balance += amount;
} finally {
lock.unlock();
}
}
public void withdraw(int amount) {
lock.lock();
try {
balance -= amount;
} finally {
lock.unlock();
}
}
public int getBalance() {
return balance;
}
}
避免死锁:
死锁是指两个或多个线程无限期地等待对方持有的资源,导致程序无法继续执行。为避免死锁,要谨慎设计锁的获取顺序,并尽量避免嵌套锁的使用。另外,可以使用工具来检测和分析死锁问题。
案例:死锁避免
class ResourceA {
public synchronized void methodA(ResourceB resourceB) {
// 获取资源A的锁
System.out.println("methodA获取了ResourceA的锁");
try {
Thread.sleep(100);
// 尝试获取资源B的锁
resourceB.methodB();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void methodC() {
// 获取资源A的锁
System.out.println("methodC获取了ResourceA的锁");
}
}
class ResourceB {
public synchronized void methodB() {
// 获取资源B的锁
System.out.println("methodB获取了ResourceB的锁");
}
public synchronized void methodD(ResourceA resourceA) {
// 获取资源B的锁
System.out.println("methodD获取了ResourceB的锁");
try {
Thread.sleep(100);
// 尝试获取资源A的锁
resourceA.methodC();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class DeadlockAvoidanceExample {
public static void main(String[] args) {
ResourceA resourceA = new ResourceA();
ResourceB resourceB = new ResourceB();
Thread thread1 = new Thread(() -> resourceA.methodA(resourceB));
Thread thread2 = new Thread(() -> resourceB.methodD(resourceA));
thread1.start();
thread2.start();
}
}
避免竞态条件:
竞态条件是指多个线程在访问和修改共享资源时出现的不确定性结果。要避免竞态条件,可以使用同步机制、原子操作、线程安全的类等。
案例:线程安全的计数器
import java.util.concurrent.atomic.AtomicInteger;
class Counter {
private AtomicInteger count = new AtomicInteger(0);
public int incrementAndGet() {
return count.incrementAndGet();
}
public int getCount() {
return count.get();
}
}
public class ThreadSafeCounterExample {
public static void main(String[] args) {
Counter counter = new Counter();
Runnable task = () -> {
for (int i = 0; i < 1000; i++) {
counter.incrementAndGet();
}
};
Thread thread1 = new Thread(task);
Thread thread2 = new Thread(task);
thread1.start();
thread2.start();
try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Count: " + counter.getCount());
}
}
避免线程间通信问题:
当多个线程共享数据时,必须正确地进行线程间通信,以保证数据的一致性和正确性。可以使用管道、消息队列、锁、条件变量等机制来实现线程间的通信。
案例:生产者-消费者模型
import java.util.LinkedList;
import java.util.Queue;
class ProducerConsumer {
private Queue<Integer> queue = new LinkedList<>();
private final int MAX_SIZE = 10;
public void produce() throws InterruptedException {
synchronized (this) {
while (queue.size() >= MAX_SIZE) {
wait();
}
int item = (int) (Math.random() * 100);
queue.add(item);
System.out.println("Produced: " + item);
notifyAll();
}
}
public void consume() throws InterruptedException {
synchronized (this) {
while (queue.isEmpty()) {
wait();
}
int item = queue.remove();
System.out.println("Consumed: " + item);
notifyAll();
}
}
}
public class ProducerConsumerExample {
public static void main(String[] args) {
ProducerConsumer pc = new ProducerConsumer();
Runnable producerTask = () -> {
try {
while (true) {
pc.produce();
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
};
Runnable consumerTask = () -> {
try {
while (true) {
pc.consume();
Thread.sleep(2000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
};
Thread producerThread = new Thread(producerTask);
Thread consumerThread = new Thread(consumerTask);
producerThread.start();
consumerThread.start();
}
}
控制线程数量:
合理控制线程数量,防止线程过多导致系统资源耗尽或线程调度开销过大。可以使用线程池来管理和调度线程,以提高效率和灵活性。
案例:控制线程池大小
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExample {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(5);
for (int i = 0; i < 10; i++) {
Runnable task = () -> {
System.out.println("Task executed by: " + Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
};
executor.submit(task);
}
executor.shutdown();
}
}
错误处理:
在多线程程序中,及时捕获和处理线程抛出的异常很重要,否则可能导致整个应用程序崩溃。可以使用try-catch
块或Thread.UncaughtExceptionHandler
来处理异常。
案例:异常处理
class ExceptionHandlingThread implements Runnable {
@Override
public void run() {
try {
int result = 10 / 0; // 抛出算术异常
System.out.println("Result: " + result);
} catch (ArithmeticException e) {
System.out.println("Caught exception: " + e.getMessage());
}
}
}
public class ExceptionHandlingExample {
public static void main(String[] args) {
Thread thread = new Thread(new ExceptionHandlingThread());
thread.start();
}
}
避免长时间阻塞:
在多线程编程中,应尽量避免长时间的阻塞操作,如长时间的IO操作或等待其他线程的锁释放。可以使用非阻塞IO、异步操作或超时机制来避免线程长时间阻塞。
案例:避免线程长时间阻塞
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class NonBlockingServerExample {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(8080);
while (true) {
Socket socket = serverSocket.accept();
// 创建新的线程处理客户端请求
Thread thread = new Thread(() -> {
try {
// 处理socket的输入和输出
System.out.println("Processing request from client");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
});
thread.start();
}
}
}
资源管理:
在多线程环境下,要注意正确管理和释放资源,防止资源泄漏或过度占用资源。
案例:多线程资源管理
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
class ConnectionPool {
private static final int MAX_CONNECTIONS = 10;
private static final String DB_URL = "jdbc:mysql://localhost:3306/db";
private static final String USER = "root";
private static final String PASSWORD = "password";
private static Connection[] connections = new Connection[MAX_CONNECTIONS];
private static boolean[] isConnectionFree = new boolean[MAX_CONNECTIONS];
static {
for (int i = 0; i < MAX_CONNECTIONS; i++) {
try {
connections[i] = DriverManager.getConnection(DB_URL, USER, PASSWORD);
isConnectionFree[i] = true;
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public synchronized Connection getConnection() {
while (true) {
for (int i = 0; i < MAX_CONNECTIONS; i++) {
if (isConnectionFree[i]) {
isConnectionFree[i] = false;
return connections[i];
}
}
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public synchronized void releaseConnection(Connection connection) {
for (int i = 0; i < MAX_CONNECTIONS; i++) {
if (connections[i] == connection) {
isConnectionFree[i] = true;
break;
}
}
notifyAll();
}
}
public class ConnectionPoolingExample {
public static void main(String[] args) {
ConnectionPool connectionPool = new ConnectionPool();
Runnable task = () -> {
Connection connection = connectionPool.getConnection();
System.out.println("Got connection: " + connection);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
connectionPool.releaseConnection(connection);
System.out.println("Released connection: " + connection);
}
};
for (int i = 0; i < 20; i++) {
new Thread(task).start();
}
}
}
监控和调试:
在开发和部署多线程应用程序时,要进行充分的监控和调试,及时发现和解决潜在的问题。可以使用工具和框架来帮助监控线程状态、调试并发问题等。
案例:监控和调试
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MonitoringAndDebuggingExample {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(5);
for (int i = 0; i < 10; i++) {
Runnable task = () -> {
System.out.println("Task executed by: " + Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
};
executor.submit(task);
}
executor.shutdown();
}
}
测试和验证:
针对多线程应用程序,要进行充分的测试和验证,包括并发测试、压力测试、性能测试等,以确保程序的正确性和稳定性。
案例:并发测试和性能测试
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ConcurrencyAndPerformanceTestingExample {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(10);
for (int i = 0; i < 100; i++) {
Runnable task = () -> {
System.out.println("Task executed by: " + Thread.currentThread().getName());
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
};
executor.submit(task);
}
executor.shutdown();
}
}