目录
Callable接口
ReentrantLock
synchronized 和 ReentrantLock之间的区别
信号量Semaphore
CountDownLatch
Callable接口
Callable接口和Runnable接口并列关系
返回值call()
泛型参数
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
public class Demo40 {
public static void main(String[] args) {
//此处Callable只是定义了一个“带有返回值”的任务
//并没有真的在执行,执行还是需要搭配Thread对象
Callable<Integer> callable = new Callable<Integer>() {
@Override
public Integer call() throws Exception {
int ret = 0;
for (int i = 1; i <= 100; i++) {
ret += i;
}
return ret;
}
};
FutureTask<Integer> futureTask = new FutureTask<>(callable);
Thread t = new Thread(futureTask);
t.start();
System.out.println(futureTask.get());
}
}
Thread的构造方法,没有提供版本传入Callable对象
Thread本身不提供获取结果的方法
就需要凭FutureTask对象来拿到结果
public class Demo41 {
private static int total = 0;
public static void main(String[] args) throws InterruptedException {
Runnable runnable = new Runnable() {
@Override
public void run() {
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum += 0;
}
total = sum;
}
};
Thread t =new Thread(runnable);
t.start();
t.join();
System.out.println(total);
}
}
ReentrantLock
可重⼊互斥锁. 和 synchronized 定位类似, 都是⽤来实现互斥效果, 保证线程安全.
和synchronized是并列关系
更经典风格的锁
import java.util.concurrent.locks.ReentrantLock;
public class Demo42 {
private static int count = 0;
public static void main(String[] args) {
ReentrantLock locker = new ReentrantLock();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 5000; i++) {
locker.lock();
try{
count++;
}finally {
locker.unlock();
}
}
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 5000; i++) {
locker.lock();
try{
count++;
}finally {
locker.unlock();
}
}
}
});
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
synchronized 和 ReentrantLock之间的区别
1.synchronized 是关键字(内部实现是jvm内部通过c++实现的)ReentrantLock标准库的类(Java)
2.synchronized通过代码块控制加锁解锁,ReentrantLock需要lock/unlock方法,需要注意unlock不被调用的问题
3.ReentrantLock除了提供lock,unlock之外还提供了一个方法tryLock()
tryLock不会阻塞
加锁成功返回true,失败返回false
调用者判定返回值决定接下来咋做
设置超时时间
等待时间达到超时时间在返回true/false
4.ReentrantLock提供了公平锁的实现
ReentrantLock locker = new ReentrantLock(true);
默认是非公平的
5.ReentrantLock搭配的等待通知机制是Condition类,相比wait,notify来说功能更强大一些
信号量Semaphore
能够协调多个进程之间的资源分配
也能协调多个线程之间的资源分配
申请acquire一个资源,计数器就会-1,p操作
释放release一个资源,计数器就会+1,v操作
计数器为0,继续申请就会阻塞等待
import java.util.concurrent.Semaphore;
public class Demo43 {
public static void main(String[] args) throws InterruptedException {
Semaphore semaphore = new Semaphore(4);
semaphore.acquire();
System.out.println("进行一次p操作");
semaphore.acquire();
System.out.println("进行一次p操作");
semaphore.acquire();
System.out.println("进行一次p操作");
semaphore.acquire();
System.out.println("进行一次p操作");
}
}
信号量的一个特殊情况,初始值为1 的信号量
取值要么是1要么是0(二元信号量)
等价于“锁”(普通的信号量,就相当于锁的更广泛的推广)
如果是普通的N的信号量,就可以限制同时有多少个线程来执行某个逻辑
import java.util.concurrent.Semaphore;
public class Demo44 {
private static int count = 0;
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(1);
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 5000; i++) {
try {
semaphore.acquire();
count++;
semaphore.release();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 5000; i++) {
try {
semaphore.acquire();
count++;
semaphore.release();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
});
t1.start();
t2.start();
}
}
CountDownLatch
同时等待N个任务执行结束
使用多线程经常把一个大的任务拆分成多个子任务
使用多线程执行这些子任务,从而提高程序的效率
1.构造方法指定参数,描述拆成了多少个任务
2.每个任务执行完毕之后,都调用一次countDown方法
如果指定10个任务,当一共调用了10次countDown说明任务全都完成了
3.主线程中调用await方法,等待所以任务执行完毕
await就会返回/阻塞等待
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Demo45 {
public static void main(String[] args) throws InterruptedException {
CountDownLatch latch = new CountDownLatch(10);
ExecutorService executor = Executors.newFixedThreadPool(4);
for (int i = 0; i < 10; i++) {
int id = i;
executor.submit(()->{
System.out.println("子任务开始执行"+id);
try {
Thread.sleep(1000);
}catch (InterruptedException e){
throw new RuntimeException(e);
}
System.out.println("子任务结束执行"+id);
});
}
latch.await();//阻塞等待所有的任务结束
System.out.println("所有任务执行完毕");
executor.shutdown();
}
}