ip做网站,网站建设现在什么服务器比较好,网页设计动态效果怎么制作,用什么网站做头像目录
Callable
ReentrantLock
Semaphore
CountDownLatch JUC即 java.util.concurrent#xff0c;其中存放了一些进行多线程编程时有用的类
Callable
Callable是一个接口#xff0c;在我们实现Runnable创建线程时#xff0c;Runnable关注的是其过程#xff0c;而不关注…目录
Callable
ReentrantLock
Semaphore
CountDownLatch JUC即 java.util.concurrent其中存放了一些进行多线程编程时有用的类
Callable
Callable是一个接口在我们实现Runnable创建线程时Runnable关注的是其过程而不关注其执行结果其返回值为void而Callable会关注执行结果Callable提供了call方法其返回值就是线程执行任务得到的结果
因此当我们在编写多线程代码时希望得到线程种代码的返回值时就可以使用Callable
例如一个线程需要实现 1 2 3 ... 100并返回其结果
若我们使用实现Runnable的方式创建线程时
public class Demo1 {public static void main(String[] args) throws InterruptedException {Thread t new Thread(new Runnable() {Overridepublic void run() {int ret 0;for (int i 1; i 100; i) {ret i;}}});t.start();t.join();}
}
若此时主线程需要获取到其计算结果则需要使用一个成员变量来保存结果
public class Demo1 {private static int sum 0;public static void main(String[] args) throws InterruptedException {Thread t new Thread(new Runnable() {Overridepublic void run() {int ret 0;for (int i 1; i 100; i) {ret i;}sum ret;//保存结果}});t.start();t.join();System.out.println(sum);}
}
而若我们使用Callable时 CallableV 其中泛型参数表示返回值的类型 CallableInteger callable new CallableInteger() {Overridepublic Integer call() throws Exception {int ret 0;for (int i 1; i 100; i) {ret i;}return ret;}};
此时就不必引入额外的成员变量了直接使用返回值即可
然而Thread未提供构造函数来传入callable 此时我们需要使用 FutureTask 来作为Thread和callable的“粘合剂”
将callable实例使用FutureTask包装一下再在构造方法传入FutureTask
此时线程就会执行FutureTask内部的Callable中的call方法计算完成后就将结果放入FutureTask对象中 FutureTaskV 泛型参数表示结果的类型 此时在主线程中调用FutureTask中的get()方法带有阻塞功能等待计算完毕从FutureTask中获取到结果
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;public class Demo {public static void main(String[] args) throws ExecutionException, InterruptedException {CallableInteger callable new CallableInteger() {Overridepublic Integer call() throws Exception {int ret 0;for (int i 1; i 100; i) {ret i;}return ret;}};FutureTaskInteger futureTask new FutureTask(callable);Thread t new Thread(futureTask);t.start();//此时无需使用join,使用futureTask中的get()方法获取到结果System.out.println(futureTask.get());}
}
观察两种实现方式我们可以发现
使用Callable和FutureTask使代码简化了很多且不用使用成员变量来保存结果
Callable和Runnable相对都是描述一个“任务”Callable描述的是带有返回值的任务Runnable描述的是不带返回值的任务
Callable通常需要搭配FutureTask使用FutureTask用来保存Callable的返回结果
ReentrantLock
ReentrantLock是一种可重入互斥锁与synchronized类似都是用来实现互斥效果保证线程安全的
ReentrantLock的用法 lock()加锁若获取不到锁就死等 unlock()解锁 tryLock(超时时间)加锁若获取不到锁等待时间一定后就放弃加锁 当我们在使用ReentrantLock时需要加锁和解锁两个操作因此当我们在加锁后很容易忘记解锁例如在unlock之前触发了异常 或 return语句此时就可能不会执行unlock
因此为了保证unlock的执行我们可以将其放在finally中
例如
ReentrantLock lock new ReentrantLock();
lock.lock();
try{//执行代码
}finally {lock.unlock();
}
synchronzied使用时无需手动释放锁ReentrantLock使用时需要手动释放使用起来更加灵活但也容易漏掉unlock 为什么有了synchronized后还有ReentrantLock? 1. ReentrantLock提供了tryLock操作。lock直接进行加锁当加锁失败时就阻塞而tryLock尝试进行加锁若加锁失败等待一定时间后不阻塞直接放弃加锁返回 false表示加锁失败
2. ReentrantLock提供了公平锁的实现遵循“先来后到”规则即等待时间长的线程先获取到锁。通过队列来记录加锁线程的先后顺序ReentrantLock默认是非公平锁在构造方法中传入true 则可设置为公平锁
3. 更强大的唤醒机制。synchronized搭配wait和notify来实现等待唤醒每次随机唤醒一个等待的线程而ReentrantLock搭配Condition类来实现通知等待机制可以更精确控制唤醒某个指定的线程
Semaphore
信号量Semaphore用来表示“可用资源的个数”其本质就是一个计数器 当申请资源时可用资源数 -1信号的P操作 当释放资源时可用资源数 1信号的V操作 Semaphore中的加减计算操作都是原子的可以在多线程环境下直接使用
信号量也是操作系统提供的机制JVM对其对应的API进行封装因此我们可用直接通过Java代码来调用这里的相关操作
Semaphore类中acquire()方法表示申请资源P操作release()方法表示释放资源V操作
例如
public class Demo2 {public static void main(String[] args) {Semaphore semaphore new Semaphore(5);//有5个可用资源for (int i 0; i 10; i) {Thread t new Thread(new Runnable() {Overridepublic void run() {try{System.out.println(申请资源);semaphore.acquire();System.out.println(获取到资源);Thread.sleep(1000);System.out.println(释放资源);semaphore.release();}catch (InterruptedException e){e.printStackTrace();}}});t.start();}}
}CountDownLatch
同时等待多个任务执行结束
例如构造CountDownLatch实例latch初始化n表示有n个任务需要完成。
在任务执行完毕时调用countDown()方法告知latch当前任务执行完毕则CountDownLatch内部的计数器 -1
在主线程中调用latch.await()阻塞等待所有任务都执行完毕计数器为0
import java.util.Random;
import java.util.concurrent.CountDownLatch;public class Demo3 {public static void main(String[] args) throws InterruptedException {CountDownLatch latch new CountDownLatch(10);//此时有10个任务需要完成for (int i 0; i 10; i) {int id i;Thread t new Thread(()-{Random random new Random();int time (random.nextInt(5) 1) * 1000;//执行任务的时间try {Thread.sleep(time);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(id 任务执行结束);//告知latch执行结束latch.countDown();});t.start();}//通过await来等待所有任务执行结束latch.await();System.out.println(所有任务都已执行完成);}
}