并发编程陷阱:Java多线程并发错误示例
在编写和执行Java多线程程序时,可能会遇到一些并发错误。以下是一些典型的错误示例:
死锁:
此现象发生在两个或多个线程互相等待对方释放资源的情况。
示例代码(避免死锁的一种方式是使用超时或者条件变量):// 线程A和B,共享资源r1和r2
class ThreadA extends Thread {
private Object r1;
public ThreadA(Object r1) {
this.r1 = r1;
}
@Override
public void run() {
synchronized (r1) { // 互斥使用r1
r1.notifyAll(); // 唤醒等待r1的线程
}
try {
r1.wait(); // 等待被通知的r1
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class ThreadB extends Thread {
private Object r2;
public ThreadB(Object r2) {
this.r2 = r2;
}
@Override
public void run() {
synchronized (r2) { // 互斥使用r2
r2.notifyAll(); // 唤醒等待r2的线程
}
try {
r2.wait(); // 等待被通知的r2
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
ThreadA threadA = new ThreadA(r1);
ThreadB threadB = new ThreadB(r2);
threadA.start(); // 开始线程A
threadB.start(); // 开始线程B
// 等待两个线程都执行完毕
threadA.join();
threadB.join();
竞态条件(Race Condition):
当多个线程同时访问和修改共享资源时,可能会导致结果不一致。
示例代码:class Counter {
private int count;
public Counter() {
count = 0;
}
public synchronized void increment() {
count++;
}
public synchronized int getValue() {
return count;
}
}
// 多个线程共享的资源
Counter counter = new Counter();
ThreadA threadA = new ThreadA(counter);
ThreadB threadB = new ThreadB(counter);
threadA.start(); // 开始线程A
threadB.start(); // 开始线程B
// 等待两个线程都执行完毕
threadA.join();
threadB.join();
System.out.println("Counter Value: " + counter.getValue()); // 输出结果
无锁编程(Lock-Free Programming)错误:
当多线程需要避免同步锁时,可能会出现数据不一致的情况。
例如,在一个计数器的更新过程中,如果直接改变共享变量而没有锁定或原子操作,就可能引发竞态条件。资源泄漏(Resource Leak):
如果线程在执行完毕后没有正确释放它所持有的资源,那么这些资源可能会一直被占用。
例如,使用Thread.currentThread().getName()
获取当前线程名,如果在线程结束时忘记关闭这个连接,就会导致资源泄漏。
通过理解和避免以上错误,可以编写更健壮、高效的多线程程序。
还没有评论,来说两句吧...