目录
一、并发编程
1、Callable接口
Callable接口方法:
1.V call():计算结果,如果无法计算结果,则抛出一个异常。
Callable接口和Runnable接口区别?
1、Callable接口有返回值,Runnable接口没有返回值
2、Callable接口call方法可以抛出异常,Runnable接口中run方法不能抛出异常
3、实现方法名不同一个是call一个是run
FutureTask是Runnable接口的一个实现类,并且此实现类的构造方法和Callable有关。
所以可通过FutureTask来创建Callable接口的多线程任务。
FutureTask是Runnable接口的一个实现类,并且此实现类的构造方法和Callable有关。
public class FutureTask<V>extends Objectimplements RunnableFuture<V>
FutureTask构造方法:
1.FutureTask(Callable<V> callable):创建一个 FutureTask,一旦运行就执行给定的Callable
2.FutureTask(Runnable runnable, V result):创建一个 FutureTask,一旦运行就执行给定的
Runnable,并安排成功完成时 get 返回给定的结果
FutureTask常用的方法:
1.boolean cancel(boolean mayInterruptIfRunning):试图取消对此任务的执行。
2.protected void done():当此任务转换到状态 isDone(不管是正常地还是通过取消)时,
调用受保护的方法。
3.V get():如有必要,等待计算完成,然后获取其结果。
4.V get(long timeout, TimeUnit unit):如有必要,最多等待为使计算完成所给定的时间之后,
获取其结果(如果结果可用)。
5.boolean isCancelled():如果在任务正常完成前将其取消,则返回 true。
6.boolean isDone():如果任务已完成,则返回 true。
7.void run():除非已将此 Future 取消,否则将其设置为其计算的结果。
8.protected boolean runAndReset():执行计算而不设置其结果,然后将此 Future 重置为
初始状态,如果计算遇到异常或已取消,则该操作失败。
9.protected void set(V v):除非已经设置了此 Future 或已将其取消,否则将其结果设置为
给定的值。
10.protected void setException(Throwable t):除非已经设置了此 Future 或已将其取消,
否则它将报告一个 ExecutionException,并将给定的 throwable 作为其原因。
Callable接口和Runnable接口示例:
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class ThreadDemo6 {
public static void main(String[] args) throws Exception {
new Thread(new MyThread1(),"A").start();
FutureTask<Integer> futureTask = new FutureTask<Integer>(new MyThread2());
FutureTask<Integer> futureTask2 = new FutureTask<Integer>(() ->{
return 300;
});
new Thread(futureTask2,"B").start();
new Thread(futureTask,"C").start();
while (!futureTask2.isDone()) {
System.out.println("wait...");
}
System.out.println(futureTask2.get());
}
}
class MyThread1 implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+" in Runnable");
}
}
class MyThread2 implements Callable<Integer>{
@Override
public Integer call() throws Exception {
System.out.println(Thread.currentThread().getName()+" in callable");
return 200;
}
}
2、JUC辅助类
2.1、减少计数CountDownLatch
CountDownLatch
public class CountDownLatchextends Object
用给定的计数 初始化 CountDownLatch。由于调用了countDown()方法,所以在当前计数到达零之前,
await 方法会一直受阻塞。
CountDownLatch构造方法:
1.CountDownLatch(int count):构造一个用给定计数初始化的 CountDownLatch。
CountDownLatch常用方法:
1.void await():使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断。
2.boolean await(long timeout, TimeUnit unit):使当前线程在锁存器倒计数至零之前
一直等待,除非线程被中断或超出了指定的等待时间。
3.void countDown():递减锁存器的计数,如果计数到达零,则释放所有等待的线程。
4.long getCount():返回当前计数。
5.String toString():返回标识此锁存器及其状态的字符串。
CountDownLatch示例:
/**
* 6个同学陆续离开教室,班长锁门
*/
public class CountDownLatchDemo {
public static void main(String[] args) {
for (int i = 1; i <= 6; i++) {
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + " 号同学离开了教室");
},String.valueOf(i)).start();
}
System.out.println(Thread.currentThread().getName() + " 班长锁门走人");
}
}
运行结果:
2 号同学离开了教室
6 号同学离开了教室
5 号同学离开了教室
4 号同学离开了教室
main 班长锁门走人
1 号同学离开了教室
3 号同学离开了教室
造成人没有走但是已经锁门的问题现象....怎么解决呢?
import java.util.concurrent.CountDownLatch;
/**
* 6个同学陆续离开教室,班长锁门
*/
public class CountDownLatchDemo {
public static void main(String[] args) throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(6);
for (int i = 1; i <= 6; i++) {
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + " 号同学离开了教室");
countDownLatch.countDown();//计数减一
},String.valueOf(i)).start();
}
countDownLatch.await();
System.out.println(Thread.currentThread().getName() + " 班长锁门走人");
}
}
运行结果:
2 号同学离开了教室
6 号同学离开了教室
5 号同学离开了教室
3 号同学离开了教室
4 号同学离开了教室
1 号同学离开了教室
main 班长锁门走人
CountDownLatch:让一些线程阻塞直到另一些线程完成一系列操作后才被唤醒
CountDownLatch主要有两个方法,当一个或多个线程调用await方法时,调用线程会被阻塞。其他线程调用countDown方法会将计数器减1(调用countDown方法的线程不会阻塞),当计数器的值变为零时,调用await方法被阻塞的线程会被唤醒,继续执行。
2.2、循环栅栏CyclicBarrier
CyclicBarrier
public class CyclicBarrierextends Object
一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。
在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用。
因为该 barrier 在释放等待线程后可以重用,所以称它为循环的 barrier。
CyclicBarrier构造方法:
1.CyclicBarrier(int parties):创建一个新的 CyclicBarrier,它将在给定数量的参与者(线程)
处于等待状态时启动,但它不会在启动 barrier 时执行预定义的操作。
2.CyclicBarrier(int parties, Runnable barrierAction):创建一个新的 CyclicBarrier,
它将在给定数量的参与者(线程)处于等待状态时启动,并在启动 barrier 时执行给定的屏障操作,
该操作由最后一个进入 barrier 的线程执行。
CyclicBarrier常用方法:
1.int await():在所有参与者都已经在此 barrier 上调用 await 方法之前,将一直等待。
2.int await(long timeout, TimeUnit unit):在所有参与者都已经在此屏障上调用 await
方法之前将一直等待,或者超出了指定的等待时间。
3.int getNumberWaiting():返回当前在屏障处等待的参与者数目。
4:int getParties():返回要求启动此 barrier 的参与者数目。
5.boolean isBroken():查询此屏障是否处于损坏状态。
6.void reset():将屏障重置为其初始状态。
CyclicBarrier示例:
import java.util.concurrent.CyclicBarrier;
//集齐七颗龙珠就可以召唤神龙许愿
public class CyclicBarrierDemo {
private static final int NUMBER = 7;
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(NUMBER,()->{
System.out.println("***集齐七颗龙珠就可以召唤神龙***");
});
for (int i = 1; i <=7; i++) {
new Thread(() -> {
try {
System.out.println(Thread.currentThread().getName() + " 星龙珠被收集到了");
cyclicBarrier.await();
} catch (Exception e) {
e.printStackTrace();
}
},String.valueOf(i)).start();
}
}
}
运行结果:
1 星龙珠被收集到了
4 星龙珠被收集到了
5 星龙珠被收集到了
6 星龙珠被收集到了
7 星龙珠被收集到了
2 星龙珠被收集到了
3 星龙珠被收集到了
***集齐七颗龙珠就可以召唤神龙***
2.3、信号灯Semaphore
信号量主要用于两个目的
一个是用于多个共享资源的互斥使用
另一个用于并发线程数的控制。
Semaphore
public class Semaphoreextends Objectimplements Serializable
Semaphore 通常用于限制可以访问某些资源(物理或逻辑的)的线程数目。
Semaphore构造方法:
1.Semaphore(int permits):创建具有给定的许可数和非公平的公平设置的Semaphore。
2.Semaphore(int permits, boolean fair):创建具有给定的许可数和给定的公平设置的Semaphore。
Semaphore常用方法:
1.void acquire():从此信号量获取一个许可,在提供一个许可前一直将线程阻塞,否则线程被中断。
2.void acquire(int permits):从此信号量获取给定数目的许可,在提供这些许可前一直将线程阻塞,
或者线程已被中断。
3.void acquireUninterruptibly():从此信号量中获取许可,在有可用的许可前将其阻塞。
4.void acquireUninterruptibly(int permits):从此信号量获取给定数目的许可,在提供这些许
可前一直将线程阻塞。
5.int availablePermits():返回此信号量中当前可用的许可数。
6.int drainPermits():获取并返回立即可用的所有许可。
7.protected Collection<Thread> getQueuedThreads():返回一个 collection,包含可能等待获取
的线程。
8.int getQueueLength():返回正在等待获取的线程的估计数目。
9.boolean hasQueuedThreads():查询是否有线程正在等待获取。
10.boolean isFair():如果此信号量的公平设置为 true,则返回 true。
11.protected void reducePermits(int reduction):根据指定的缩减量减小可用许可的数目。
12.void release():释放一个许可,将其返回给信号量。
13.void release(int permits):释放给定数目的许可,将其返回到信号量。
14.String toString():返回标识此信号量的字符串,以及信号量的状态。
15.boolean tryAcquire():仅在调用时此信号量存在一个可用许可,才从信号量获取许可。
16.boolean tryAcquire(int permits):仅在调用时此信号量中有给定数目的许可时,才从此信号量
中获取这些许可。
17.boolean tryAcquire(int permits, long timeout, TimeUnit unit):如果在给定的等待时间内
此信号量有可用的所有许可,并且当前线程未被中断,则从此信号量获取给定数目的许可。
18.boolean tryAcquire(long timeout, TimeUnit unit):如果在给定的等待时间内,此信号量有可
用的许可并且当前线程未被中断,则从此信号量获取一个许可。
Semaphore示例:
import java.util.Random;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
//6辆汽车,停在3个停车位里
public class SemaphoreDemo {
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(3);
for (int i = 1; i <=6; i++) {
new Thread(()->{
try {
semaphore.acquire();//抢占车位
System.out.println(Thread.currentThread().getName() + " 抢到了车位");
TimeUnit.SECONDS.sleep(new Random().nextInt(5));//设置随机停车时间
System.out.println(Thread.currentThread().getName() + " ----离开了车位");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
semaphore.release();
}
},String.valueOf(i)).start();
}
}
}
运行结果:
1 抢到了车位
3 抢到了车位
2 抢到了车位
2 ----离开了车位
4 抢到了车位
4 ----离开了车位
3 ----离开了车位
5 抢到了车位
6 抢到了车位
1 ----离开了车位
6 ----离开了车位
5 ----离开了车位
每天⽤⼼记录⼀点点。内容也许不重要,但习惯很重要!
一个程序员最重要的能力是:写出高质量的代码!!
有道无术,术尚可求也,有术无道,止于术。
无论你是年轻还是年长,所有程序员都需要记住:时刻努力学习新技术,否则就会被时代抛弃!