目录
前言:
Callable
ReentrantLock
Semaphore
CountDownLatch
前言:
在Java中,JUC(包路径:java.util.concurrent)是一个用于并发编程的包,提供了线程安全的集合类、同步工具、并发执行框架和原子变量等,以简化和增强多线程编程的性能和可靠性。接下来介绍的这几个组件使用起来都比较简单。
Callable
Callable是一个接口,你可以理解成它是一个带有返回值的Runnable。
如图,Runnable和Callable的创建对比:
Thread类没有关于Callable的构造方法。原因在于需要通过Callable的实例创建FutureTask的实例才行:
public class CallableTest {
public static void main(String[] args) throws InterruptedException, ExecutionException {
Callable<Integer> callable=new Callable<Integer>() {
@Override
public Integer call() throws Exception {
System.out.println("hehhe");
return 10;
}
};
/**在创建线程的时候,多出了创建FutureTask的对象这一步*/
FutureTask<Integer> futureTask=new FutureTask<>(callable);
Thread thread=new Thread(futureTask);
thread.start();
thread.join();
/*get方法可以获取到返回值*/
int ret=futureTask.get();
System.out.println("thread:"+ret);
}
}
FutureTask是一个类,它的get方法可以获取call方法的返回值。
执行结果:
hehhe
thread:10
ReentrantLock
除了synchronized,Java标准库开提供了其他方式对线程进行加锁的操作。
比如:Excuters(第10节线程池讲过)、Semaphore(等一下会讲)、ReentrantLock(当前正题)等。
ReentrantLock是一个类(需要创建对象使用),与synchronized对比,ReentrantLock的区别:
- 加锁方式:需要用到lock()/unlock()来上锁解锁,因此为了避免死锁,最好把unlock()放到finally块中。
- tryLock:ReentrantLock提供了tryLock(),调用此方法,如果加锁失败,当前线程不会进入阻塞状态,而是直接返回,执行别的任务。
- 公平锁:ReentrantLock默认是不公平锁,不过可以在使用构造方法的时候设置成公平锁。
- 更精确的通知:ReentrantLock实现了Condition接口,在这个接口中,提供了一组方法,可以精确的唤醒某个满足特定条件的线程。而synchronized只能随机或全部唤醒。
Semaphore
Semaphore是计算机的一个专业术语,意为“信号量”。
它是一个控制资源访问的同步类工具。它可以限制同时访问某一个特定资源的总线程数量,保证多个线程可以有序的访问共享资源。
举个形象的例子:
在停车场的入口,我们通常会看到这个显示剩余车位的指示牌:
Semaphore就可以类比成这个指示牌。用了这个指示牌,外面的车子就不会无脑的开进去,在车位满了的时候就不会出现拥堵。
Semaphore的使用方式:
public class SemaphoreTest {
public static void main(String[] args) {
Semaphore semaphore=new Semaphore(4);
for (int i = 0; i <20 ; i++) {
int id=i;
Thread t=new Thread(()->{
try {
System.out.println("申请资源");
semaphore.acquire();//申请资源的方法
System.out.println("执行任务:"+id);
System.out.println("释放资源");
semaphore.release();//释放资源的方法
} catch (InterruptedException e) {
e.printStackTrace();
}
});
t.start();
}
}
}
如果Semaphore构造方法的参数设置成1,那么它就变成了一个加锁操作,一个线程在完成了任务后,其他线程才可以继续执行。
CountDownLatch
CountDownLatch是JUC中的一个同步辅助类,用它的构造方法可以设置一个任务数量,每次执行完一个任务,可以调用它自带的contDown()方法任务计数器会-1。当任务计数器为0的时候,可以唤醒其他线程(调用了CountDownLatch类的'await()'方法的线程,这个方法可以让调用它的线程进入睡眠直到任务计数器减为0)。
代码演示:
public class JUCcountDown {
public static void main(String[] args) throws InterruptedException {
ExecutorService service= Executors.newFixedThreadPool(4);
CountDownLatch latch=new CountDownLatch(20);
for (int i = 0; i <20 ; i++) {
int id=i;
service.submit(()->{
System.out.println("执行任务:"+id);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("任务:"+id+"执行完毕");
latch.countDown();//计数器-1
});
}
//主线程进入睡眠,计数器为0才会苏醒
latch.await();
System.out.println("所有任务执行完毕!");
}
}