Java中同步与并发用法分析
同步
在Java中,同步是指多个线程之间访问共享资源的时候,保证线程安全的机制。Java提供了两种机制来实现同步:synchronized关键字和Lock接口。
synchronized关键字
synchronized关键字可以用于修饰方法或代码块。被修饰的方法或代码块在同一时间只能被一个线程执行,其他线程需要等待。
示例代码:
public class ThreadSafeExample {
private int count = 0;
// synchronized关键字修饰方法
public synchronized void increment() {
count++;
}
public int getCount() {
return count;
}
}
在上述例子中,increment()方法被synchronized关键字修饰,意味着在同一时间只有一个线程能够访问它。如果不加synchronized关键字,多个线程同时访问increment()方法可能会出现线程安全问题。
Lock接口
Lock接口提供了与synchronized关键字类似的同步机制,也可以用于保证多个线程之间的线程安全。
示例代码:
public class ThreadSafeExample {
private int count = 0;
private Lock lock = new ReentrantLock(); // 实例化Lock接口对象
public void increment() {
lock.lock(); // 加锁
try {
count++;
} finally {
lock.unlock(); // 解锁
}
}
public int getCount() {
return count;
}
}
在上述例子中,我们使用了Lock接口提供的ReentrantLock实现类来实例化lock对象。在increment()方法中,我们调用了lock()方法加锁,finally中调用了unlock()方法解锁。这样,在同一时间只有一个线程能够访问increment()方法,可以保证线程安全。
并发
Java中的并发是指多个线程同时执行,在同一时间内,每个线程都可以访问共享资源。
Java提供了多种工具来处理并发,最常用的有:
- Semaphore信号量
- CountDownLatch计数器
- CyclicBarrier屏障
Semaphore信号量
Semaphore可以用来控制同时访问共享资源的线程数量。Semaphore类似于一个计数器,可以通过acquire()和release()方法来控制资源的访问。
示例代码:
public class SemaphoreExample {
private static final int THREAD_COUNT = 10;
private static Semaphore semaphore = new Semaphore(5); // 实例化Semaphore对象,初始许可数量为5
public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 0; i < THREAD_COUNT; i++) {
executorService.execute(() -> {
try {
semaphore.acquire(); // 获取许可
System.out.println(Thread.currentThread().getName() + " acquire a permit");
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release(); // 释放许可
System.out.println(Thread.currentThread().getName() + " release a permit");
}
});
}
executorService.shutdown();
}
}
在上述例子中,Semaphore的初始许可数量为5,每个线程获取一个许可,线程执行结束后释放许可。最多只有5个线程能够同时占用许可,其他线程需要等待。
CountDownLatch计数器
CountDownLatch可以用来实现等待其他线程执行完毕之后再进行操作。CountDownLatch的初始计数器数量为线程个数,每个线程执行完后计数器数量减1,当计数器数量为0时,await()方法才会返回。
示例代码:
public class CountDownLatchExample {
private static final int THREAD_COUNT = 5;
private static CountDownLatch countDownLatch = new CountDownLatch(THREAD_COUNT); // 实例化CountDownLatch对象,计数器数量为5
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 0; i < THREAD_COUNT; i++) {
executorService.execute(() -> {
try {
System.out.println(Thread.currentThread().getName() + " started");
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName() + " ended");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
countDownLatch.countDown(); // 计数器减1
}
});
}
countDownLatch.await(); // 等待计数器归零
System.out.println("All threads have finished.");
executorService.shutdown();
}
}
在上述例子中,我们创建了5个线程,执行其中的任务,任务执行完成后调用countDown()方法减少计数器数量。执行主线程中,通过await()方法等待所有线程执行完毕,当计数器数量变为0时,执行主线程中的代码。
CyclicBarrier屏障
CyclicBarrier可以用来在多个线程之间创建一个屏障,只有所有线程到达屏障时,才会继续执行后续操作。
示例代码:
public class CyclicBarrierExample {
private static final int THREAD_COUNT = 5;
private static CyclicBarrier cyclicBarrier = new CyclicBarrier(THREAD_COUNT, () -> {
System.out.println("All threads have reached the barrier.");
}); // 实例化CyclicBarrier对象,等待线程数量为5
public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 0; i < THREAD_COUNT; i++) {
executorService.execute(() -> {
try {
System.out.println(Thread.currentThread().getName() + " started");
Thread.sleep(2000);
cyclicBarrier.await(); // 等待其他线程到达屏障
System.out.println(Thread.currentThread().getName() + " ended");
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
});
}
executorService.shutdown();
}
}
在上述例子中,我们创建了5个线程,执行其中的任务,并在其中增加了cyclicBarrier.await()方法。当线程调用这个方法时,它就等待其他线程也到达这个屏障。当所有线程都到达屏障时,CyclicBarrier的内部计数器就会被重置为其初始值,并启动一个可选的Runnable。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java中同步与并发用法分析 - Python技术站