浅谈Java多线程实现及同步互斥通讯
引言
多线程是指一种多个线程执行完毕后可以得到更好的系统性能的机制。Java多线程的实现是通过创建Thread实例或者继承Thread类并重写它的run()方法来完成的。Java也提供了一个Java.util.concurrent包,它为Java多线程编程提供了更多的助力。在多线程编程中,同步互斥是一种非常重要的问题,它可以确保多个线程协同工作时不会出现死锁、竞态条件和其它不安全的情况。
Java多线程实现
通过继承Thread类实现
下面这个例子演示了如何通过继承Thread类来实现多线程。
class MyThread extends Thread {
@Override
public void run() {
// 这里可以放置线程的任务代码
}
}
public class TestMyThread {
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start();
}
}
通过运行TestMyThread类,该程序会创建一个新的线程并开始运行。
通过Runnable接口实现
下面这个例子演示了如何通过实现Runnable接口来实现多线程。
class MyRunnable implements Runnable {
@Override
public void run() {
// 这里可以放置线程的任务代码
}
}
public class TestMyRunnable {
public static void main(String[] args) {
MyRunnable runnable = new MyRunnable();
Thread thread = new Thread(runnable);
thread.start();
}
}
通过运行TestMyRunnable类,该程序会创建一个新的线程并开始运行。
同步互斥
当多个线程访问共享资源时,就有可能会出现多个线程访问同一资源的情况,这时就需要同步互斥来保护共享资源。Java提供了两种方法来实现同步互斥:synchronized关键字和Lock接口。
synchronized关键字
我们可以使用synchronized关键字来保护代码块或者方法,使得多个线程必须获得锁才能执行这个代码块或方法。下面是一个使用synchronized关键字的例子。
class Counter {
private int count = 0;
public synchronized void increment() {
count++;
}
public synchronized void decrement() {
count--;
}
public synchronized int getCount() {
return count;
}
}
public class TestCounter {
public static void main(String[] args) {
Counter counter = new Counter();
// 创建多线程对计数器进行操作
}
}
上面的代码创建了一个计数器类,接着我们在Counter类的increment()、decrement()和getCount()方法上都加上了synchronized关键字。这样就可以保证在多个线程同时访问这些方法时,只有一个线程可以获得锁并执行方法,其它线程则必须等待。
Lock接口
另外一种实现同步互斥的方式是使用Lock接口。与synchronized关键字不同的是,Lock接口使用时需要程序员主动获取锁和释放锁。下面是一个使用Lock接口的例子。
class Counter {
private int count = 0;
private Lock lock = new ReentrantLock();
public void increment() {
lock.lock();
try {
count++;
} finally {
lock.unlock();
}
}
public void decrement() {
lock.lock();
try {
count--;
} finally {
lock.unlock();
}
}
public int getCount() {
return count;
}
}
public class TestCounter {
public static void main(String[] args) {
Counter counter = new Counter();
// 创建多线程对计数器进行操作
}
}
上面的代码创建了一个计数器类,接着我们在Counter类中添加了一个Lock接口类型的成员变量lock。然后在increment()、decrement()方法中使用lock.lock()获取锁,并在finally块中使用lock.unlock()释放锁。这样就可以保证每个线程进入这个方法时必须先获得锁,如果没有得到锁则线程进入等待状态。
示例
示例1:线程安全的懒汉式单例模式
public class Singleton {
private static Singleton instance;
private static Lock lock = new ReentrantLock();
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
lock.lock();
try {
if (instance == null) {
instance = new Singleton();
}
} finally {
lock.unlock();
}
}
return instance;
}
}
上面的代码实现了一个线程安全的懒汉式单例模式。在getInstance()方法中我们使用了Lock接口来实现同步互斥,确保在多个线程同时获取单例对象时不会出现问题。
示例2:多线程实现带判断Condition的生产者消费者模式
public class ProduceConsume {
private LinkedList<Integer> list = new LinkedList<>();
private Lock lock = new ReentrantLock();
private Condition notFull = lock.newCondition();
private Condition notEmpty = lock.newCondition();
private final int MAXSIZE = 5;
public void produce() {
lock.lock();
try {
while (list.size() == MAXSIZE) {
notFull.await();
}
int num = new Random().nextInt(10);
list.add(num);
System.out.println("生产者生产了" + num);
notEmpty.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void consume() {
lock.lock();
try {
while (list.size() == 0) {
notEmpty.await();
}
int num = list.removeFirst();
System.out.println("消费者消费了" + num);
notFull.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
上面的代码实现了一个带判断Condition的生产者消费者模式。使用Lock接口的实例的Condition对象,使生产者要在容器满的时候停止生产,并等待消费者来消费;消费者要在容器空的时候停止消费,并等待生产者来生产。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:浅谈Java多线程实现及同步互斥通讯 - Python技术站