在Java函数中如何实现线程同步?
Java中实现线程同步通常有两种方式:synchronized和Lock。
synchronized关键字是一种内置锁,使用这种锁可以确保同一时刻只有一个线程可以访问被锁定的代码块或方法。其中,在Java中的每个对象都有一个与之关联的内置锁,它被称为监视器锁(或管程锁),当一个线程在一个对象上执行synchronized方法时,它必须先获得这个对象的监视器锁,然后才能执行方法体。
synchronized可以使用在方法和代码块上。在方法上使用synchronized会将整个方法中的代码都锁住,而在代码块上使用则只会锁住代码块中的代码。
以下是synchronized的示例:
public class MyThread implements Runnable {
private int count = 0;
public synchronized void increment() {
count++;
}
public void run() {
for (int i = 0; i < 10000; i++) {
increment();
}
}
public static void main(String[] args) throws InterruptedException {
MyThread myThread = new MyThread();
Thread thread1 = new Thread(myThread);
Thread thread2 = new Thread(myThread);
thread1.start();
thread2.start();
thread1.join(); //等待线程1执行完
thread2.join(); //等待线程2执行完
System.out.println(myThread.count);
}
}
在上面的示例中,我们创建了一个MyThread类,这个类有一个increment方法用来实现count变量的自增,increment方法前加上synchronized关键字使得该方法成为同步方法,只允许同一时刻只能有一个线程访问该方法。
使用synchronized在代码块上的示例:
public class MyThread implements Runnable {
private int count = 0;
private Object lock = new Object();
public void increment() {
synchronized (lock) {
count++;
}
}
public void run() {
for (int i = 0; i < 10000; i++) {
increment();
}
}
public static void main(String[] args) throws InterruptedException {
MyThread myThread = new MyThread();
Thread thread1 = new Thread(myThread);
Thread thread2 = new Thread(myThread);
thread1.start();
thread2.start();
thread1.join(); //等待线程1执行完
thread2.join(); //等待线程2执行完
System.out.println(myThread.count);
}
}
在上面的示例中,我们使用了一个Object类型的lock对象来加锁。需要注意的是,lock对象必须是共享的,否则不同线程会持有不同的锁,从而无法达到同步的目的。
除了synchronized外,Java还提供了一种支持更灵活的锁,就是Lock。相对于synchronized而言,Lock的控制粒度更细,可以控制锁的获取和释放,支持多个条件变量,也支持公平锁和非公平锁。
Lock的示例:
public class MyThread implements Runnable {
private int count = 0;
private Lock lock = new ReentrantLock();
public void increment() {
lock.lock();
try {
count++;
} finally {
lock.unlock();
}
}
public void run() {
for (int i = 0; i < 10000; i++) {
increment();
}
}
public static void main(String[] args) throws InterruptedException {
MyThread myThread = new MyThread();
Thread thread1 = new Thread(myThread);
Thread thread2 = new Thread(myThread);
thread1.start();
thread2.start();
thread1.join(); //等待线程1执行完
thread2.join(); //等待线程2执行完
System.out.println(myThread.count);
}
}
在上面的示例中,我们使用了Lock对象来加锁,lock.lock()获取锁,lock.unlock()释放锁。
总结来说,Java的线程同步机制主要有synchronized和Lock两种方式。synchronized是一种内置锁,使用简单,但是如果使用不当可能会出现死锁的情况。而Lock相对来说控制的粒度更细,可以更加灵活地控制锁的获取和释放,但是使用起来相对复杂,需要了解和掌握更多的API。根据具体业务场景,选择适合的方式进行线程同步。
