1. 共享变量与同步机制
多个线程可以通过共享对象的变量进行通信,但为了避免数据不一致的问题,必须使用同步机制来控制对共享变量的访问。
使用
synchronized关键字:synchronized确保在同一时刻只有一个线程可以执行同步代码块。它可以同步方法或代码块,用于保护共享数据。示例:
class counter {
private int count = 0;
public synchronized void increment() {
count++;
}
public synchronized int getcount() {
return count;
}
}
public class syncexample {
public static void main(string[] args) {
counter counter = new counter();
thread t1 = new thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
thread t2 = new thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (interruptedexception e) {
e.printstacktrace();
}
system.out.println("final count: " + counter.getcount());
}
}使用场景:用于保护共享资源,防止多个线程同时读写导致数据不一致的问题。
使用
volatile关键字:volatile确保一个线程对变量的修改对其他线程立即可见。它适用于轻量级的变量同步,通常用于标志位控制。示例:
class flag {
private volatile boolean running = true;
public void stop() {
running = false;
}
public boolean isrunning() {
return running;
}
}
public class volatileexample {
public static void main(string[] args) {
flag flag = new flag();
thread t1 = new thread(() -> {
while (flag.isrunning()) {
system.out.println("thread is running");
}
system.out.println("thread stopped");
});
t1.start();
try {
thread.sleep(2000);
} catch (interruptedexception e) {
e.printstacktrace();
}
flag.stop();
}
}使用场景:用于控制线程的退出、开关操作等轻量级场景。
2. wait()、notify() 和 notifyall()
object 类的这三个方法用于在同步块内实现线程间的协作。线程可以通过 wait() 进入等待状态,直到另一个线程调用 notify() 或 notifyall() 唤醒它们。
wait():当前线程进入等待状态,并释放锁。notify():唤醒一个正在等待同一锁的线程。notifyall():唤醒所有等待同一锁的线程。
示例:生产者-消费者模型
class sharedresource {
private int value;
private boolean hasvalue = false;
public synchronized void produce(int newvalue) throws interruptedexception {
while (hasvalue) {
wait(); // 等待消费者消费
}
value = newvalue;
hasvalue = true;
system.out.println("produced: " + value);
notify(); // 唤醒消费者
}
public synchronized void consume() throws interruptedexception {
while (!hasvalue) {
wait(); // 等待生产者生产
}
system.out.println("consumed: " + value);
hasvalue = false;
notify(); // 唤醒生产者
}
}
public class producerconsumerexample {
public static void main(string[] args) {
sharedresource resource = new sharedresource();
thread producer = new thread(() -> {
try {
for (int i = 0; i < 5; i++) {
resource.produce(i);
thread.sleep(100);
}
} catch (interruptedexception e) {
e.printstacktrace();
}
});
thread consumer = new thread(() -> {
try {
for (int i = 0; i < 5; i++) {
resource.consume();
thread.sleep(200);
}
} catch (interruptedexception e) {
e.printstacktrace();
}
});
producer.start();
consumer.start();
}
}使用场景:适用于线程间的协调工作,比如生产者-消费者模型,一个线程负责生产资源,另一个线程负责消费资源。
3. lock 和 condition 接口
相比 synchronized,lock 提供了更灵活的同步机制,而 condition 可以替代 wait()、notify() 和 notifyall(),并支持多个等待条件。
reentrantlock:常用于显式锁控制,可以提供公平锁机制(按获取锁的顺序进行调度)。condition:类似于object的wait()、notify(),可以创建多个condition来进行复杂的线程协调。
示例:
import java.util.concurrent.locks.condition;
import java.util.concurrent.locks.lock;
import java.util.concurrent.locks.reentrantlock;
class boundedbuffer {
private final int[] buffer;
private int count, in, out;
private final lock lock = new reentrantlock();
private final condition notfull = lock.newcondition();
private final condition notempty = lock.newcondition();
public boundedbuffer(int size) {
buffer = new int[size];
}
public void put(int value) throws interruptedexception {
lock.lock();
try {
while (count == buffer.length) {
notfull.await(); // 等待缓冲区未满
}
buffer[in] = value;
in = (in + 1) % buffer.length;
count++;
notempty.signal(); // 唤醒消费线程
} finally {
lock.unlock();
}
}
public int take() throws interruptedexception {
lock.lock();
try {
while (count == 0) {
notempty.await(); // 等待缓冲区非空
}
int value = buffer[out];
out = (out + 1) % buffer.length;
count--;
notfull.signal(); // 唤醒生产线程
return value;
} finally {
lock.unlock();
}
}
}
public class lockconditionexample {
public static void main(string[] args) {
boundedbuffer buffer = new boundedbuffer(5);
thread producer = new thread(() -> {
try {
for (int i = 0; i < 10; i++) {
buffer.put(i);
system.out.println("produced: " + i);
}
} catch (interruptedexception e) {
e.printstacktrace();
}
});
thread consumer = new thread(() -> {
try {
for (int i = 0; i < 10; i++) {
int value = buffer.take();
system.out.println("consumed: " + value);
}
} catch (interruptedexception e) {
e.printstacktrace();
}
});
producer.start();
consumer.start();
}
}使用场景:适用于需要显式锁定、更复杂的条件等待场景,比如多条件同步、多生产者-消费者模型。
4. java.util.concurrent 包的并发工具
java 提供了 java.util.concurrent 包下的一系列高级并发工具类来简化线程间通信。
- blockingqueue:线程安全的队列,常用于生产者-消费者模式。
- countdownlatch:允许一个或多个线程等待其他线程完成某些操作。
- cyclicbarrier:多个线程在某个点上相互等待,直到所有线程到达该点。
- semaphore:用于控制对资源的访问许可。
- exchanger:用于两个线程之间交换数据。
到此这篇关于java线程之间通信的几种方式详解的文章就介绍到这了,更多相关java线程之间通信内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论