欢迎访问宙启技术站
智能推送

Java中的多线程函数:如何实现线程互斥?

发布时间:2023-07-03 21:35:55

在Java中,实现线程互斥主要有以下几种方式:

1. 使用synchronized关键字:synchronized关键字可以将一个方法或一个代码块标记为临界区,保证同一时间只能有一个线程执行该区域的代码。当一个线程进入synchronized代码块时,其他线程会被阻塞,直到进入线程执行完临界区的代码。

示例代码:

public class MutexExample {
    private static int counter = 0;
    
    public static void main(String[] args) {
        Thread thread1 = new Thread(() -> {
            synchronized (MutexExample.class) { // 使用类对象作为锁
                for (int i = 0; i < 1000; i++) {
                    counter++;
                }
            }
        });
        
        Thread thread2 = new Thread(() -> {
            synchronized (MutexExample.class) { // 使用类对象作为锁
                for (int i = 0; i < 1000; i++) {
                    counter--;
                }
            }
        });
        
        thread1.start();
        thread2.start();
        
        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        System.out.println("Counter: " + counter);
    }
}

在上述代码中,使用synchronized关键字将线程1和线程2中的临界区代码块进行了同步,保证了对counter变量的互斥访问。

2. 使用ReentrantLock类:ReentrantLock是Java提供的一个显示锁(独占锁),可以使用lock()方法获得锁,使用unlock()方法释放锁。与synchronized关键字相比,ReentrantLock提供了更加灵活的锁定机制,可以支持可重入性、公平性等特性。

示例代码:

public class MutexExample {
    private static int counter = 0;
    private static Lock lock = new ReentrantLock();
    
    public static void main(String[] args) {
        Thread thread1 = new Thread(() -> {
            lock.lock();
            try {
                for (int i = 0; i < 1000; i++) {
                    counter++;
                }
            } finally {
                lock.unlock();
            }
        });
        
        Thread thread2 = new Thread(() -> {
            lock.lock();
            try {
                for (int i = 0; i < 1000; i++) {
                    counter--;
                }
            } finally {
                lock.unlock();
            }
        });
        
        thread1.start();
        thread2.start();
        
        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        System.out.println("Counter: " + counter);
    }
}

在上述代码中,使用ReentrantLock类的lock()和unlock()方法来替代了synchronized关键字。使用try-finally语句块是为了保证锁的释放,在finally块中调用unlock()方法来释放锁。

3. 使用Semaphore类:Semaphore是Java提供的一个计数信号量,它可以控制同时访问某个资源的线程数量。当线程要访问该资源时,首先要从Semaphore获取许可证,如果许可证数小于等于0,线程会被阻塞。当线程访问完毕后,要归还许可证给Semaphore。

示例代码:

public class MutexExample {
    private static int counter = 0;
    private static Semaphore semaphore = new Semaphore(1);
    
    public static void main(String[] args) {
        Thread thread1 = new Thread(() -> {
            try {
                semaphore.acquire();
                for (int i = 0; i < 1000; i++) {
                    counter++;
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                semaphore.release();
            }
        });
        
        Thread thread2 = new Thread(() -> {
            try {
                semaphore.acquire();
                for (int i = 0; i < 1000; i++) {
                    counter--;
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                semaphore.release();
            }
        });
        
        thread1.start();
        thread2.start();
        
        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        System.out.println("Counter: " + counter);
    }
}

在上述代码中,使用Semaphore类来实现对counter变量的互斥访问。Semaphore的构造函数传入的参数表示许可证的数量,这里传入1表示同时只允许一个线程访问资源。acquire()方法用于获取许可证,如果没有许可证则会被阻塞,release()方法用于释放许可证。

总结:以上是在Java中实现线程互斥的几种方式,分别是使用synchronized关键字、ReentrantLock类和Semaphore类。在实际开发中,根据不同的需求和场景选择合适的方式来实现线程互斥,以确保多线程程序的正确性和数据的一致性。