理解和避免:Java多线程同步问题示例
在Java多线程编程中,同步问题是非常常见的。当多个线程同时访问和修改共享资源时,如果没有适当的控制,就可能导致数据不一致或者程序崩溃。
以下是一些典型的Java多线程同步问题的示例:
竞态条件(Race Condition):两个或多个线程同时执行一个操作,导致预期结果未出现。
```java
class Counter {
private int count = 0;public synchronized void increment() {
count++;
}
public synchronized int decrement() {
if (count > 0) {
count--;
}
return count;
}
public synchronized int getCount() {
return count;
}
}
public class Main {
public static void main(String[] args) {
Counter counter = new Counter();
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 5; i++) {
counter.increment();
}
}));
Thread thread2 = new Thread(() -> {
for (int i = 4; i >= 0; i--) {
counter.decrement();
}
}));
thread1.start();
thread2.start();
// 这里可能会导致程序错误,因为无法保证线程执行的顺序和同步条件
// counter.getCount();
try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Counter count: " + counter.getCount()); // 输出:Counter count: 0
}
}
2. **死锁(Deadlock)**:两个或多个线程相互等待对方释放资源,导致都无法继续执行。
```java
class LockResource {
private Object resource = new Object();
public synchronized void acquire() {
while (resource != null) { // 假设一个资源只能被一个线程持有
try:
wait();
catch (InterruptedException e) {
e.printStackTrace();
}
}
resource = new Object(); // 赋予资源
}
public synchronized void release() {
if (resource != null) { // 检查资源是否被占用
resource = null; // 取消资源
notifyAll(); // 通知所有等待的线程资源已释放
}
}
}
public class Main {
public static void main(String[] args) {
LockResource lockResource = new LockResource();
Thread thread1 = new Thread(() -> {
try {
lockResource.acquire();
System.out.println("Thread 1 acquired resource.");
} catch (InterruptedException e) {
e.printStackTrace();
}
}));
Thread thread2 = new Thread(() -> {
try {
lockResource.acquire(); // 此处会阻塞,直到thread1释放资源
System.out.println("Thread 2 acquired resource.");
} catch (InterruptedException e) {
e.printStackTrace();
}
}));
thread1.start();
thread2.start();
try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
lockResource.release(); // 在main方法结束前释放资源
}
}
饥饿问题(Starvation):一个线程可能因为等待某个条件满足而长时间得不到执行机会,导致资源被其他线程长时间占用。
```java
class SynchronizedCounter {
private int count = 0;public synchronized void increment() {
count++;
}
public synchronized int decrement() {
if (count > 0) {
count--;
}
return count;
}
public synchronized boolean isEmpty() {
return count == 0;
}
}
public class Main {
public static void main(String[] args) {
SynchronizedCounter counter = new SynchronizedCounter();
Thread thread1 = new Thread(() -> {
for (int i = 5; i > 0; i--) { // 这个循环会无限次执行
counter.increment();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}));
thread1.start();
while (!counter.isEmpty())) { // 当计数器不为空时循环
System.out.println("Counter count: " + counter.decrement());
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
thread1.join(); // 等待线程结束
System.out.println("Counter count after thread join: " + counter.getCount())); // 此时计数器应该已经被释放
}
}``
以上示例中,线程1无限次执行循环,导致同步问题。为了避免这些问题,通常需要使用适当的并发控制机制,如
synchronized关键字、
ReentrantLock`等。
还没有评论,来说两句吧...