1、创建线程的几种方式
a、继承Thread
b、实现Runnable接口
c、实现Callable接口
d、线程池
2、Runnable和Callable的不同
a、Runnable没有返回值,Callable有返回值
b、Runnable不会抛出异常,Callable在返回结果计算错误时候抛出异常
c、实现方式名称不同,Runnable是run方法,Callable是call方法
3、FutureTask
FutureTask是Runnable的实现类,是未来任务,他具备比Runnable更强大的功能,可以使用FutureTask来实现Callable的创建,以下是简单代码实现
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class callableDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//实现Runnable
new Thread(new MyThread01(),"A").start();
//实现Callable
FutureTask<Integer> task=new FutureTask<>(new MyThread02());
new Thread(task,"A").start();
System.out.println(task.get());
//因为Callable是函数式接口,所以可使用lamda表达式完成匿名函数方式直接返回结果
FutureTask<Integer> task1=new FutureTask<>(()->{
System.out.println(Thread.currentThread().getName()+"进来了");
return 2;
});
new Thread(task1,"B").start();
while (!task1.isDone()){
System.out.println("还在计算中....");
}
System.out.println(task1.get());
new Thread(task1,"C").start();
System.out.println(task1.get());
}
}
class MyThread01 implements Runnable{
@Override
public void run() {
System.out.println("Runnable线程");
}
}
class MyThread02 implements Callable {
@Override
public Integer call() throws Exception {
System.out.println(Thread.currentThread().getName()+"进来了");
return 1;
}
}
下图是运行结果,可见,未来任务是只需要汇总一次的,线程B去执行过一次,打印"B进来了“,得到了返回值2之后,线程C再去执行直接得到结果2
4、JUC辅助类之CountDownLatch
一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。举例:比如班里有6个同学和一个班长,班长需要等6个同学都走了之后才能锁门离开,那么班长的角色就是CountDownLatch的意思,此工具类叫减少计数
import java.util.concurrent.CountDownLatch;
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("班长离开了");
}
}
5、JUC辅助类之CyclicBarrier
一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用。因为该 barrier 在释放等待线程后可以重用,所以称它为循环 的 barrier。
以上解释可以理解为,多个线程都完成后,可以触发的方法,比如以下代码,收集完七颗龙珠后,可以召唤神龙,此工具类叫循环栅栏
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierDemo {
private static final Integer number=7;
public static void main(String[] args) {
CyclicBarrier barrier=new CyclicBarrier(number,()->{
System.out.println("集齐七颗龙珠,即将召唤神龙!");
});
for (int i = 1; i <=7 ; i++) {
new Thread(()->{
try {
System.out.println(Thread.currentThread().getName()+"星龙珠被收集了");
barrier.await();
} catch (Exception e) {
e.printStackTrace();
}
},String.valueOf(i)).start();
}
}
}
6、JUC辅助类之Semaphore
一个计数信号量。从概念上讲,信号量维护了一个许可集。如有必要,在许可可用前会阻塞每一个 acquire(),然后再获取该许可。每个 release() 添加一个许可,从而可能释放一个正在阻塞的获取者。但是,不使用实际的许可对象,Semaphore
只对可用许可的号码进行计数,并采取相应的行动。
以上解释可以理解为,线程间可以抢占有限的资源,有某一个线程完成后可以由其他线程再次竞争,比如以下代码案例,有6个汽车,3个停车位,第一次可以停满3个车为,三个车等待停车,由其中一个车离开之后,其余的3个车抢占那个车位,此工具类叫信号灯
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) {
//3个车位
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();
}
}
}