深入探究Java中不同的线程间数据通信方式
多线程编程中,线程的运行是并发的,若多个线程共享同一块数据,需要设置线程间数据通信以确保线程的安全并发执行。Java提供了多种线程间数据通信的方式。
1. 共享变量方式
在多线程的场景中,共享变量是指被多个线程共同使用和修改的变量。这种方式是最简单的线程间通信方式,可以在任何地方使用,但要注意线程安全问题。
在Java中,最常用的共享变量方式是 volatile 和 synchronized,分别对应修改变量与锁同步。
1.1 volatile
volatile关键字在多线程编程中保证数据的同步,能够强制到线程内存中读取变量而不是线程缓存,从而确保数据的可见性。
示例:
public class VolatileTest {
private volatile boolean flag = false;
public void start() {
new Thread(new Runnable() {
@Override
public void run() {
while (!flag) {
// do something
}
System.out.println("Thread is end.");
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
flag = true;
}
}).start();
}
}
在上面的示例中,通过 volatile 关键字保证了 flag 的可见性,确保了第二个线程对 flag 的修改能够被第一个线程同步到。
1.2 synchronized
synchronized是Java中一个重要的关键字,在多线程的场景中,被用来管理共享数据的访问。通过 synchronized 锁机制可以保证代码的原子执行。
示例:
public class SynchronizedTest {
private int count = 0;
public synchronized void increment() {
count++;
}
public void start() {
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
increment();
}
System.out.println("Thread is end.");
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
increment();
}
System.out.println("Thread is end.");
}
}).start();
}
}
在上面的示例中,线程共同对 count 进行操作,通过 synchronized 关键字锁住 increment() 方法,确保了对 count 的操作是原子性的。
2. wait/notify方式
Java中 wait/notify方式是一种非常重要的线程间通信方式,他们一起被用来实现线程的同步。wait可以将线程挂起,notify可以唤醒其它线程。
2.1 wait
wait()方法挂起当前线程,此方法必须在synchronized代码块或方法内调用。wait()会释放线程占用的锁,让其它线程进入synchronized代码块或方法内。
示例:
public class WaitNotifyTest {
private final Object monitor = new Object();
public void start() {
new Thread(new Runnable() {
@Override
public void run() {
synchronized (monitor) {
System.out.println("Thread1 start.");
try {
monitor.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread1 end.");
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
synchronized (monitor) {
System.out.println("Thread2 start.");
monitor.notify();
System.out.println("Thread2 end.");
}
}
}).start();
}
}
在上面的示例中,通过 notify() 方法唤醒线程1。由于 wait() 方法释放了锁,线程2 执行完成后,线程1 才会执行。
2.2 notify
notify() 方法唤醒在此对象监视器上等待的一个线程,如果有多个线程等待,将随机唤醒其中的一个。
示例:
public class WaitNotifyTest {
private final Object monitor = new Object();
public void start() {
new Thread(new Runnable() {
@Override
public void run() {
synchronized (monitor) {
System.out.println("Thread1 start.");
try {
monitor.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread1 end.");
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
synchronized (monitor) {
System.out.println("Thread2 start.");
monitor.notify();
System.out.println("Thread2 end.");
}
}
}).start();
}
}
在上面的示例中,通过 notify() 方法唤醒线程1。由于 wait() 方法释放了锁,线程2 执行完成后,线程1 才会执行。
3. Lock/Condition方式
Lock/Condition方式是一种替代synchronized的方式,它们的功能类似,但是比synchronized更加灵活。按照具体的场景,选择合适的方式。
示例:
public class LockConditionTest {
private final Lock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();
public void start() {
new Thread(new Runnable() {
@Override
public void run() {
lock.lock();
System.out.println("Thread1 start.");
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread1 end.");
lock.unlock();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
lock.lock();
System.out.println("Thread2 start.");
condition.signal();
System.out.println("Thread2 end.");
lock.unlock();
}
}).start();
}
}
在上面的示例中,一个 lock 指定了访问临界区的线程,一个 condition 指定了需要等待的线程,当需要等待时,等待线程在 condition 上等待。
结论
在多线程编程中,线程间数据通信方式很多,选择合适的方式可以提高程序的性能和效率,保证代码的正确性和可读性。以上介绍的共享变量方式、wait/notify方式、Lock/Condition方式是其中最常用的方式,这里还需要提醒大家,线程安全问题是多线程编程中需要注意的关键点,需要谨慎对待。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:深入探究一下Java中不同的线程间数据通信方式 - Python技术站