Java-多线程解析1
一、线程的描述:
1、线程是一个应用程序进程中不同的执行路径比例如:一个WEB服务器,能够为多个用户同时提供请求服务;而 -> 进程是操作系统中正在执行的不同的应用程序,比如:我们可以同时打开系统的word和游戏
2、多线程随处不在,例如:平常用电脑办公的时候,一边听着歌一边做事,此时电脑的状态就是多线程;向平常玩手机看直播的时候,一边看着直播,一边聊着WX,此时手机的状态就是多线程;提高了用户的体验度以及画面的效应速率,生活中随处可见;
3、三大特性:
3.1、原子性:提供互斥访问,同一时刻只能有一个线程对数据进行操作(Atomic、CAS算法、synchronized、Lock)
3.2、可见性:一个主内存的线程如果进行了修改,可以及时被其他线程观察到(synchronized、volatile)
3.3、有序性:如果两个线程不能从 happens-before原则 观察出来,那么就不能观察他们的有序性,虚拟机可以随意的对他们进行重排序,导致其观察观察结果杂乱无序(happens-before原则)
二、线程的作用:
1、举例说:把一个人花费30天完成的事情 变成10个人化3天就能完成,目的时为了提高程序的效率
2、为了解决CPU利用率问题,提高CPU利用
3、平时开发的时候,点击某一个操作时,通过同一个条件访问2个接口,将结果数据展示到页面;
3.1、传统的做法:按照顺序依次访问2个接口,那么数据最后展示的时间就是2个接口返回结果总和;
3.2、异多线程做法:将方法放入异步线程中,线程启动后就去抢CPU执行权,谁先拿到谁先执行,线程同时发起请求,数据的执行时间= 其中某个线程返回结果的最长的时间;
3.3、同步多线程:
synchronized 是Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。
三、线程的生命周期:
四、线程的实现方式:
有三种:继承Thread类、实现Runnable接口、实现Callable接口(不常用)
1、继承Thread方式:
1-1:继承Thread类,重写run方法;
1-2:线程启动后,谁先抢到CPU执行权,谁就先执行
public class JavaStudyThread extends Thread {public JavaStudyThread(String name) {super(name);}//自定义线程对象,继承Thread,重写run()方法@Overridepublic void run() {// 线程执行体for (int i = 1; i < 3; i++) {System.out.println("公平竞争->"+Thread.currentThread().getName() + "--" + "主动出击" + i + "次,得到了我");}}public static void main(String[] args) {//创建线程实现类对象,调用start()方法启动线程new JavaStudyThread("小老婆1").start();new JavaStudyThread("小老婆2").start();for (int i = 1; i < 6; i++) {System.out.println("公平竞争->"+"大老婆--" + "主动出击" + i + "次,得到了我");}} }
输出结果:说明谁抢到主动权,谁就可以先拥有我
公平竞争->大老婆--主动出击1次,得到了我 公平竞争->小老婆2--主动出击1次,得到了我 公平竞争->小老婆1--主动出击1次,得到了我 公平竞争->大老婆--主动出击2次,得到了我 公平竞争->小老婆2--主动出击2次,得到了我 公平竞争->小老婆1--主动出击2次,得到了我 公平竞争->大老婆--主动出击3次,得到了我 公平竞争->大老婆--主动出击4次,得到了我 公平竞争->大老婆--主动出击5次,得到了我
2、实现Runnable接口:
2-1:实现Runnable接口,重写run方法
2-2:谁先抢到CPU执行权,谁就先执行
public class JavaStudyThread implements Runnable {// 自定义线程对象,实现Runnable接口,重写run()方法@Overridepublic void run() {for (int i = 1; i < 3; i++) {System.out.println("公平竞争->"+Thread.currentThread().getName() + "--" + "主动出击" + i + "次,得到了我");}}public static void main(String[] args) {// 创建实现类对象JavaStudyThread javaStudyThread = new JavaStudyThread();// 创建代理类对象Thread thread = new Thread(javaStudyThread,"小老婆1");Thread thread2 = new Thread(javaStudyThread,"小老婆2");// 调用start()方法启动线程thread.start();thread2.start();for (int i = 1; i < 6; i++) {System.out.println("公平竞争->"+"大老婆--" + "主动出击" + i + "次,得到了我");}} }
输出结果:说明谁抢到主动权,谁就可以先拥有我
公平竞争->大老婆--主动出击1次,得到了我 公平竞争->小老婆1--主动出击1次,得到了我 公平竞争->大老婆--主动出击2次,得到了我 公平竞争->小老婆1--主动出击2次,得到了我 公平竞争->小老婆2--主动出击1次,得到了我 公平竞争->小老婆2--主动出击2次,得到了我 公平竞争->大老婆--主动出击3次,得到了我 公平竞争->大老婆--主动出击4次,得到了我 公平竞争->大老婆--主动出击5次,得到了我
3、实现Callable接口(不常用)
3-1:实现Callable接口,定义返回值类型
3-2:重写call()方法,并抛出异常
3-3:谁先抢到CPU执行权,谁就先执行
public class JavaStudyThread implements Callable<Boolean> {@Overridepublic Boolean call() throws Exception {for (int i = 0; i < 4; i++) {System.out.println("自定义" + Thread.currentThread().getName() + "->" + i);}return true;}public static void main(String[] args) throws ExecutionException, InterruptedException {// 创建实现类对象JavaStudyThread thread = new JavaStudyThread();JavaStudyThread thread2 = new JavaStudyThread();// 创建执行服务,参数是线程池线程数量ExecutorService ser = Executors.newFixedThreadPool(2);// 提交执行Future<Boolean> res = ser.submit(thread);Future<Boolean> res2 = ser.submit(thread2);// 获取结果boolean r1 = res.get();boolean r2 = res2.get();// 关闭服务ser.shutdownNow();}/*输出结果:自定义pool-1-thread-2->0自定义pool-1-thread-2->1自定义pool-1-thread-2->2自定义pool-1-thread-1->0自定义pool-1-thread-1->1自定义pool-1-thread-2->3自定义pool-1-thread-1->2自定义pool-1-thread-1->3*/
}
五、多线程常用的一些控制方法:
sleep方法:同步(synchronized )
设定线程阻塞的时间,先让从“运行状态”进入到“休眠(阻塞)状态”,等待设定的时间过去,从“(阻塞)状态”变成“就绪状态” 每一个对象都有一个锁,sleep不会释放锁。public class JavaStudyThread implements Runnable{private int count = 20;public void run() {while (true) {if (count <= 0) {System.out.println("已卖完");return;}getCount();}}public synchronized void getCount() {if(count==0){System.out.println("已卖完");return;}System.out.println(Thread.currentThread().getName() + "-->售出第:" + (21 - count) + "票");count--;try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}}public static void main(String[] args){JavaStudyThread t1 = new JavaStudyThread();Thread thread= new Thread(t1);Thread thread1= new Thread(t1);thread.start();thread1.start();} }
wait方法:
设定线程阻塞的时间,先让从“运行状态”进入到“休眠(阻塞)状态”,释放同步锁,等待设定的时间过去,从“(阻塞)状态”变成“就绪状态” 每一个对象都有一个锁;public class JavaStudyThread {private static String str = "test";public void run() {new Thread(new Runnable() {@Overridepublic void run() {synchronized (str) {while (true) {try {System.out.println(str);str.wait();System.out.println(str);} catch (InterruptedException e) {e.printStackTrace();}}}}}).start();}public static void main(String[] args) {new JavaStudyThread().run();System.out.println("111111");} }
yield方法:
- 提出申请释放CPU资源,至于能否成功释放取决于JVM决定。- 调用yield()方法后,线程仍然处于RUNNABLE状态,线程不会进入阻塞状态。- 调用yield()方法后,线程处于RUNNABLE状态,就保留了随时被调用的权利。- 第一种:a/b线程释放CPU,a/b线程抢到CPU执行释放,a/b线程抢到了CPU执行权;- 第二种:a/b的所有线程执行完才释放CPU,此时a/b线程抢到CPU继续执行;public class JavaStudyThread implements Runnable {@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + "--得到了我");Thread.yield();System.out.println(Thread.currentThread().getName() + "--连续--得到了我");}public static void main(String[] args) {//创建实现类对象JavaStudyThread javaStudyThread = new JavaStudyThread();//创建线程Thread thread = new Thread(javaStudyThread, "大老婆");Thread thread1 = new Thread(javaStudyThread, "小老婆");//启动线程thread.start();thread1.start();} }
输出结果:
1.从结果1看,小老婆释放CPU成功后,大老婆就抢到了CPU执行权,接着大老婆也释放CPU成功,小老婆抢到了CPU执行权;2.从结果2看,小老婆并没有成功释放CPU,而是连续得到了我;结果1:小老婆--得到了我大老婆--得到了我小老婆--连续--得到了我大老婆--连续--得到了我结果2:小老婆--得到了我小老婆--连续--得到了我大老婆--得到了我大老婆--连续--得到了我
join方法:
- 将当前的线程挂起,当前线程阻塞,待其他的线程执行完毕,当前线程才能执行。- 可以把join()方法理解为插队,谁插到前面,谁先执行。- 如果主线程阻塞,等待 join线程 一口气执行完,主线程才能继续执行。public class JavaStudyThread implements Runnable {@Overridepublic void run() {for (int i = 0; i < 10; i++) {System.out.println(Thread.currentThread().getName() + "join()线程执行:" + i);}}public static void main(String[] args) throws InterruptedException {//创建实现类对象JavaStudyThread javaStudyThread = new JavaStudyThread();//创建线程Thread thread = new Thread(javaStudyThread, "a");//启动线程thread.start();for (int i = 0; i < 10; i++) {System.out.println("主线程执行:" + i);if (i == 2) {thread.join();//主线程阻塞,等待thread一口气执行完,主线程才能继续执行}}} }
setPriority方法:
- 改变、获取线程的优先级。- Java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程,线程调度器按照优先级决定应该调度哪个线程来执行。- 线程的优先级用数据表示,范围1~10。- 线程的优先级高只是表示他的权重大,获取CPU执行权的几率大。- 先设置线程的优先级,在执行start()方法。- 优先级高的线程不一定先执行。public class JavaStudyThread implements Runnable {@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + "线程优先级:" + Thread.currentThread().getPriority());}public static void main(String[] args) {//创建实现类对象JavaStudyThread javaStudyThread = new JavaStudyThread();//创建线程Thread thread = new Thread(javaStudyThread, "a");Thread thread1 = new Thread(javaStudyThread, "b");Thread thread2 = new Thread(javaStudyThread, "c");Thread thread3 = new Thread(javaStudyThread, "d");//先设置线程的优先级thread.setPriority(Thread.MIN_PRIORITY);//1thread1.setPriority(Thread.NORM_PRIORITY);//5thread2.setPriority(Thread.MAX_PRIORITY);//10thread3.setPriority(7);//启动线程thread.start();thread1.start();thread2.start();thread3.start();}// 执行结果:优先级高的线程不一定先执行// c线程优先级:10// b线程优先级:5// a线程优先级:1// d线程优先级:8}
setDaemon()方法:
-线程分为用户线程和守护线程。-虚拟机必须确保用户线程执行完毕。-虚拟机不用等待守护线程执行完毕。(如:后天记录操作日志、监控内存、垃圾回收等线程)。-Thread.setDeamon(booean on)方法,true:守护线程;fasle:用户进程。默认是false。-用户进行执行完毕,守护进程也就停止执行。public class JavaStudyThread {public static void main(String[] args) {//创建实现类对象DeamonThread deamon = new DeamonThread();UserThread user = new UserThread();Thread thread2 =new Thread(user);thread2.start();//创建线程Thread thread1 = new Thread(deamon);thread1.setDaemon(true);thread1.start();} } //守护进程 class DeamonThread implements Runnable {@Overridepublic void run() {// 验证虚拟机不用等待守护线程执行完毕,只要用户线程执行完毕,程序就结束。while (true){System.out.println("守护线程");}} } //用户进程 class UserThread implements Runnable{@Overridepublic void run() {for (int i =0 ;i<2;i++) {System.out.println("用户线程:" + i);}} }
isAlive方法:
-用于检查线程是否处于活动状态。活着是指已开始但尚未终止的线程。调用run方法时,线程将运行特定的时间段,然后停止执行。public class JavaStudyThread implements Runnable {@Overridepublic void run(){System.out.println("sample ");try{Thread.sleep(25);}catch (InterruptedException ie){}System.out.println("only ");}public static void main(String[] args){JavaStudyThread javaStudyThread =new JavaStudyThread();Thread my_obj_1 = new Thread(javaStudyThread);Thread my_obj_2 = new Thread(javaStudyThread);my_obj_1.start();System.out.println("第一个对象已创建并启动");my_obj_2.start();System.out.println("第二个对象已创建并启动");System.out.println(my_obj_1.isAlive());System.out.println("第一个对象上的isAlive函数已被调用");System.out.println(my_obj_2.isAlive());System.out.println("第二个对象上的isAlive函数已被调用");}/*输出结果:第一个对象已创建并启动sample第二个对象已创建并启动true第一个对象上的isAlive函数已被调用true第二个对象上的isAlive函数已被调用sampleonlyonly*/ }
六、多线程 并发 和 同步:synchronized 同步锁的使用
1、并发:
1-1、并发原因:在多线程场景下,如果同一个资源 被多个线程修改,其他线程又读取这个资源,那么就可能存在数据结果不对的问题,也就会导致线程不安全;例如:两人卖20张票;
public class JavaStudyThread implements Runnable{private int count = 20;public void run() {while (true) {if (count <= 0) {System.out.println("已卖完");return;}getCount();}}public void getCount() {if(count==0){System.out.println("已卖完");return;}System.out.println(Thread.currentThread().getName() + "-->售出第:" + (21 - count) + "票");count--;try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}}public static void main(String[] args){JavaStudyThread t1 = new JavaStudyThread();Thread thread= new Thread(t1);Thread thread1= new Thread(t1);thread.start();thread1.start();} }
Thread-0-->售出第:1票 Thread-1-->售出第:1票 Thread-1-->售出第:3票 Thread-0-->售出第:3票 Thread-0-->售出第:5票 Thread-1-->售出第:5票 Thread-1-->售出第:7票 Thread-0-->售出第:7票 Thread-1-->售出第:9票 Thread-0-->售出第:9票 Thread-0-->售出第:11票 Thread-1-->售出第:11票 Thread-0-->售出第:13票 Thread-1-->售出第:13票 Thread-0-->售出第:15票 Thread-1-->售出第:15票 Thread-1-->售出第:17票 Thread-0-->售出第:17票 Thread-1-->售出第:19票 Thread-0-->售出第:20票 已卖完 已卖完
从结果可以看出,两个人卖的票存在重复了。票号是唯一,所以这是并发异步带来的问题;
1-2、处理方法:增加同步关键字 synchronized ,让线程排队,操作共享资源要有先后顺序,一个线程操作完之后,另一个线程才能操作或者读取。
1-2-1、同步方法:public synchronized void method(int args){执行体…}
- 防止线程同步访问共享资源造成冲突。
- 变量需要同步,常量不需要同步(常量存放于方法区)。
- 多个线程访问共享资源的代码(即线程执行体)有可能是同一份代码,也有可能是不同的代码;无论是否执行同一份代码,只要这些线程的代码访问同一份可变的共享资源,这些线程之间就需要同步。
public class JavaStudyThread implements Runnable{private int count = 20;public void run() {while (true) {if (count <= 0) {System.out.println("已卖完");return;}getCount();}}public synchronized void getCount() {if(count==0){System.out.println("已卖完");return;}System.out.println(Thread.currentThread().getName() + "-->售出第:" + (21 - count) + "票");count--;try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}}public static void main(String[] args){JavaStudyThread t1 = new JavaStudyThread();Thread thread= new Thread(t1);Thread thread1= new Thread(t1);thread.start();thread1.start();} }
Thread-0-->售出第:1票 Thread-0-->售出第:2票 Thread-1-->售出第:3票 Thread-1-->售出第:4票 Thread-1-->售出第:5票 Thread-0-->售出第:6票 Thread-0-->售出第:7票 Thread-0-->售出第:8票 Thread-1-->售出第:9票 Thread-1-->售出第:10票 Thread-1-->售出第:11票 Thread-1-->售出第:12票 Thread-1-->售出第:13票 Thread-1-->售出第:14票 Thread-0-->售出第:15票 Thread-0-->售出第:16票 Thread-0-->售出第:17票 Thread-1-->售出第:18票 Thread-1-->售出第:19票 Thread-1-->售出第:20票 已卖完 已卖完 已卖完进程已结束,退出代码0
从结果可以看出:两个人分别各自卖完了手上的票;
1-2-1、同步代码块:synchronized (Obj){执行体…}
- Obj称之为同步监视器,可以是任何对象,但是推荐使用共享资源作为同步监视器。
- 不同方法中无需指定同步监视器,因为同步方法中的同步监视器就是this,就是这个对象本身,或者是class。
public class JavaStudyThread {private static String str = "test";public void run() {new Thread(new Runnable() {@Overridepublic void run() {synchronized (str) {while (true) {try {System.out.println(str);str.wait();System.out.println(str);} catch (InterruptedException e) {e.printStackTrace();}}}}}).start();}public static void main(String[] args) {new JavaStudyThread().run();System.out.println("111111");} }
七、死锁问题:
1、死锁的原因:
1-1、多个线程各自占有一个资源的时候,同时等待其他线程占有的资源才能运行。导致这些线程都在等待对方释放资源,都停止了执行。
1-2、某一个同步代码块同时拥有“两个以上对象的锁”时,就可能发生“死锁”的问题。
class Goddess{}//女神 class GirlFriend{}//女朋友 class Person extends Thread {public static Goddess goddess = new Goddess();public static GirlFriend girlFriend = new GirlFriend();int choose;String personName;public Person(int choose, String personName) {this.choose = choose;this.personName = personName;}@Overridepublic void run() {try {this.kiss();} catch (Exception e) {e.printStackTrace();}}//同步代码块中 嵌套了 同步代码块,会导致 线程一致阻塞,大家都在等待对方释放锁,也就停止了执行;private void kiss() throws InterruptedException {if (choose == 0) {synchronized (goddess) {//女神System.out.println(personName + "--亲到--女神--被女朋友发现了,女朋友分手了,死锁了");Thread.sleep(1000);synchronized (girlFriend) {//女朋友System.out.println(personName + "--亲到--女朋友--被女神发现了,女神分手了,死锁了");}}} else {synchronized (girlFriend) {System.out.println(personName + "--亲到--女朋友--被女神发现了,女朋友分手了,死锁了");Thread.sleep(1000);synchronized (goddess) {System.out.println(personName + "--亲到--女神--被女朋友发现了,女神分手了,死锁了");}}}} }public class JavaStudyThread {public static void main(String[] args) {System.out.println("人生赢家第一条,两女共处渡良宵!");System.out.println("两女拿不下,不如回家种地瓜");Person person = new Person(0, "穷男A");Person person1 = new Person(1, "穷男B");person.start();person1.start();} }
输出结果: 说明男主来到后发现女神和女朋友是闺蜜,现场被捉,思索了
人生赢家第一条,两女共处渡良宵! 两女拿不下,不如回家种地瓜 穷男B--亲到--女朋友--被女神发现了,女朋友分手了,死锁了 穷男A--亲到--女神--被女朋友发现了,女朋友分手了,死锁了
2、解决死锁--synchronized同步锁:
杜绝synchronized相互嵌套,把方法作为同级使用,如下:
class Goddess{}//女神 class GirlFriend{}//女朋友 class Person extends Thread {public static Goddess goddess = new Goddess();public static GirlFriend girlFriend = new GirlFriend();int choose;String personName;public Person(int choose, String personName) {this.choose = choose;this.personName = personName;}@Overridepublic void run() {try {this.trueKiss();} catch (Exception e) {e.printStackTrace();}}//同步代码 移到同级,杜绝相互嵌套,正确的输出结果private void trueKiss() throws InterruptedException {if (choose == 0) {synchronized (girlFriend) {System.out.println(personName + "--亲到了--女朋友,--被女神发现了,女神就加入了");Thread.sleep(1000);}synchronized (goddess) {System.out.println(personName + "--亲到了--女神,--被女朋友发现了,女朋友就加入了");}} else {synchronized (goddess) {System.out.println(personName + "--亲到了--女神,--被女朋友发现了,女朋友就加入了");Thread.sleep(1000);}synchronized (girlFriend) {System.out.println(personName + "--亲到了--女朋友,--被女神发现了,女神就加入了");}}} }public class JavaStudyThread {public static void main(String[] args) {System.out.println("人生赢家第一条,两女共处渡良宵!");System.out.println("两女拿不下,不如回家种地瓜");Person person = new Person(0, "穷男A");Person person1 = new Person(1, "穷男B");person.start();person1.start();} }
输出结果: 说明男主来到后发现女神和女朋友是闺蜜,分不开各个击破
人生赢家第一条,两女共处渡良宵! 两女拿不下,不如回家种地瓜 穷男A--亲到了--女朋友,--被女神发现了,女神就加入了 穷男B--亲到了--女神,--被女朋友发现了,女朋友就加入了 穷男B--亲到了--女朋友,--被女神发现了,女神就加入了 穷男A--亲到了--女神,--被女朋友发现了,女朋友就加入了
八、Lock(锁):同步锁
同步代码块 / 同步⽅法具有的功能 Lock 都有;
创建对象 Lock lock = new ReentrantLock() ,
public void lock() :加同步锁
public void unlock() :释放同步锁
public class JavaStudyThread implements Runnable {private static int count =10;List<Integer> list = new ArrayList<>();private final Lock lock =new ReentrantLock();@Overridepublic void run() {while (true){lock.lock();//加锁try {if(count>0){try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}list.add(count);count--;var aa = list.stream().count();System.out.println(aa);}else {break;}}finally {lock.unlock();//解锁}}}public static void main(String[] args) {JavaStudyThread javaStudyThread=new JavaStudyThread();Thread thread=new Thread(javaStudyThread);Thread thread2=new Thread(javaStudyThread);thread.start();thread2.start();}}
输出结果:按照顺序依次输出结果
1
2
3
4
5
6
7
8
9
10
九、多线程的异步方法:如果存在返回值,则代表有阻塞,那就是同步请求了。无返回值,则代表异步请求,bin
1、runAsync() 异步无参返回:
2、supplyAsync() 异步有参返回
3、allOf() 多个异步处理(针对有参返回)
ublic class JavaStudyThread {//runAsync 无参返回 不会阻塞,代表异步public void asyncThread() throws Exception {CompletableFuture async1 = CompletableFuture.runAsync(() -> {try {Thread.sleep(100);System.out.println(Thread.currentThread().getName());System.out.println("none return Async");} catch (Exception e) {e.printStackTrace();}});// 调用get()将等待异步逻辑处理完成async1.get();}//supplyAsync 有参返回 会阻塞,代表异步public void asyncThread2()throws Exception {CompletableFuture<String> async2 = CompletableFuture.supplyAsync(() -> {return "hello";});String result = async2.get();System.out.println(result);}//allOf() 多个异步处理(针对有参返回) 会阻塞,代表异步public void asyncThread3() throws ExecutionException, InterruptedException {CompletableFuture<String> async3 = CompletableFuture.supplyAsync(()->{try {Thread.sleep(6000);} catch (InterruptedException e) {e.printStackTrace();}return "a";});CompletableFuture<String> async4 = CompletableFuture.supplyAsync(()->{try {Thread.sleep(6000);} catch (InterruptedException e) {e.printStackTrace();}return "b";});CompletableFuture<String> async5 = CompletableFuture.supplyAsync(()->{try {Thread.sleep(6000);} catch (InterruptedException e) {e.printStackTrace();}return "c";});// CompletableFuture result = CompletableFuture.allOf(async3,async4,async5);Date date = new Date();SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");String timeValue = sdf.format(date);System.out.println(timeValue);var a = async3.get();var b = async4.get();var c = async5.get();Date date2 = new Date();String timeValue2 = sdf.format(date2);System.out.println(a+b+c+";"+timeValue2);// var aaa = result.get();
// String bbb = Stream.of(async3,async4,async5).map(CompletableFuture::join).collect(Collectors.joining(" "));
// System.out.println(bbb);}public static void main(String[] args) throws Exception {JavaStudyThread javaStudyThread = new JavaStudyThread();javaStudyThread.asyncThread3();}
}
4、complete:
CompletableFuture<String> future1 = new CompletableFuture<>();
future.complete("hello world"); //异步线程执行
future.whenComplete((res, throwable) -> {System.out.println(res);
});
System.out.println(future1.join());
CompletableFuture<String> future2 = new CompletableFuture<>();
future.completeExceptionally(new Throwable("failed")); //异步线程执行
System.out.println(future2.join());
5、thenApply:
String original = "Message";
CompletableFuture<String> cf = CompletableFuture.completedFuture(original).thenApply(String::toUpperCase);
System.out.println(cf.join());
6、thenCombine:
CompletableFuture<String> cf = CompletableFuture.completedFuture("Message").thenApply(String::toUpperCase);
CompletableFuture<String> cf1 = CompletableFuture.completedFuture("Message").thenApply(String::toLowerCase);
CompletableFuture<String> allCf = cf.thenCombine(cf1, (s1, s2) -> s1 + s2);
System.out.println(allCf.join());
7、allOf
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Message1");
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "Message2");
CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> "Message3");
CompletableFuture<String> future = CompletableFuture.allOf(future1, future2, future3).thenApply(v -> {String join1 = future1.join();String join2 = future2.join();String join3 = future3.join();return join1 + join2 + join3;});
System.out.println(future.join());
相关文章:

Java-多线程解析1
一、线程的描述: 1、线程是一个应用程序进程中不同的执行路径比例如:一个WEB服务器,能够为多个用户同时提供请求服务;而 -> 进程是操作系统中正在执行的不同的应用程序,比如:我们可以同时打开系统的word和游戏 2、多…...
PHP 判断用户当前坐标是否在电子围栏内
可以使用射线法判断用户当前坐标点是否在电子围栏内。 具体步骤如下: 1. 将电子围栏的四个角坐标按顺序连接成一个封闭多边形。 2. 从用户当前坐标点向外发射一条射线,判断这条射线与多边形的交点个数。 3. 如果交点个数为奇数,则用户当前…...

Java版本工程管理系统源码企业工程项目管理系统简介
一、立项管理 1、招标立项申请 功能点:招标类项目立项申请入口,用户可以保存为草稿,提交。 2、非招标立项申请 功能点:非招标立项申请入口、用户可以保存为草稿、提交。 3、采购立项列表 功能点:对草稿进行编辑&#x…...

高速缓存(cache)的原理: 了解计算机架构与性能优化
计基之存储器层次结构 Author: Once Day Date: 2023年5月9日 长路漫漫,而今才刚刚启程! 本内容收集整理于《深入理解计算机系统》一书。 参看文档: 捋一捋Cache - 知乎 (zhihu.com)iCache和dCache一致性 - 知乎 (zhihu.com)C…...
【Vue3+TS项目】硅谷甄选day04--顶部组件搭建+面包屑+路由鉴权
顶部组件搭建 顶部左侧折叠和面包屑实现 左侧菜单刷新折叠的问题解决---属性default-active 折叠之后图标不见:icon放在插槽外面----element的menu属性:collapse project\src\layout\index.vue // 获取路由对象 import { useRoute } from vue-route…...

某oa 11.10 未授权任意文件上传
漏洞简介 之前也对通达 oa 做过比较具体的分析和漏洞挖掘,前几天看到通达 oa 11.10 存在未授权任意文件上传漏洞,于是也打算对此进行复现和分析。 环境搭建 https://www.tongda2000.com/download/p2019.php 下载地址 :https://cdndown.tongda…...

Grounded Language-Image Pre-training(论文翻译)
文章目录 Grounded Language-Image Pre-training摘要1.介绍2.相关工作3.方法3.1统一构建3.2.语言感知深度融合3.3.使用可扩展的语义丰富数据进行预训练 4.迁移到既定的基准4.1.COCO上的zero-shot和监督迁移学习4.2.LVIS上的zero-shot 迁移学习4.3.Flickr30K实体上的 phrase gro…...
设计模式-行为型模式(模板方法、策略、观察者、迭代器、责任链、命令、状态、备忘录、访问者、中介者、解释器)
行为型模式:专注于对象之间的 协作 及如何通过彼此之间的交互来完成任务。行为型模式通常集中在描述对象之间的 责任 分配和 通信 机制,并提供了一些优雅解决特定问题的方案。 模板方法模式(Template Method Pattern)策略模式(Strategy Pattern)观察者模…...
全面探讨 Spring Boot 的自动装配机制
Spring Boot 是一个基于 Spring 框架的快速开发脚手架,它通过自动配置机制帮助我们快速搭建应用程序,从而减少了我们的配置量和开发成本。自动装配是 Spring Boot 的核心特点之一,它可以减少项目的依赖,简化配置文件,提…...

河道水位监测:河道水位监测用什么设备
中国地形复杂,气候多样,导致水资源分布不均,洪涝和干旱等问题时有发生。同时,人类活动也对水资源造成了很大压力,工业和农业用水增加,河道水位下降,生态环境受到威胁。因此,对河道水…...

嵌入式系统中u-boot和bootloader到底有什么区别
嵌入式软件工程师都听说过 u-boot 和 bootloader,但很多工程师依然不知道他们到底是啥。 今天就来简单讲讲 u-boot 和 bootloader 的内容以及区别。 Bootloader Bootloader从字面上来看就是启动加载的意思。用过电脑的都知道,windows开机时会首先加载…...
实验14:20211030 1+X 中级实操考试(id:2498)
实验14:20211030 1X 中级实操考试(id:2498) 一、项目背景说明二、表结构三、步骤【5 分】步骤 1:项目准备【5 分】步骤 2:完成实体类 Member【10 分】步骤 3:完成实体类 Goods【10 分】步骤 4&a…...

(字符串 ) 剑指 Offer 58 - II. 左旋转字符串 ——【Leetcode每日一题】
❓剑指 Offer 58 - II. 左旋转字符串 难度:简单 字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两位得到的…...
EPICS编程
提纲 1) 为什么在EPICS上编程 2)构建系统特性:假设基本理解Unix Make 3)在libCom中可用的工具 1) 为什么在EPICS上编程 1、社区标准:EPICS合作者知道和明白EPICS结构 2、在很多操作系统之间代码移值性…...

17:00面试,还没10分钟就出来了,问的实在是太...
从外包出来,没想到死在另一家厂子 自从加入这家公司,每天都在加班,钱倒是给的不少,所以也就忍了。没想到8月一纸通知,所有人不许加班,薪资直降30%,顿时有吃不起饭的赶脚。 好在有个兄弟内推我去…...
docker都有那些工具,及工具面试题
docker介绍 Docker 是一种开源的容器化平台,可以帮助开发者将应用程序和依赖项打包到轻量级的容器中,然后部署到任何基于 Linux 的操作系统中。使用 Docker 可以大大简化开发、部署和管理应用程序的过程,使其更加快速、灵活和可靠。 Docker…...
LAMP网站应用架构
LAMP 一、LAMP概述1、各组件的主要作用2、构建LAMP各组件的安装顺序 二、编译安装Apache httpd服务1、关闭防火墙,将安装Apache所需软件包传到/opt目录下2.安装环境依赖包3.配置软件模块4.编译及安装5.优化配置文件路径,并把httpd服务的可执行程序文件放…...
C++虚函数virtual(动态多态)(纯虚函数)
怎么判断函数是虚函数还是普通函数? 用VS,在调用对象的方法的地方。。按altg ,如果他跳转到正确的函数,那也就意味着他是编译时可以确定的。。。 但是如果他跳到了这个调用对象的基类的函数,那么也就意味着他是一个运行…...

【Java 接口】接口(Interface)的定义,implements关键字,接口实现方法案例
博主:_LJaXi Or 東方幻想郷 专栏: Java | 从入门到入坟 专属:六月一日 | 儿童节 Java 接口 接口简介 🎃接口的定义 🧧接口实现类名定义 🎁接口实现类小案例 🎈后话 🎰 接口简介 &…...

解决Vmware上的kali找不到virtualbox上的靶机的问题
解决kali找不到靶场ip问题的完整方法 1.配置靶机2.配置kali的虚拟网络3.配置kali中的eth0网络 1.配置靶机 靶机部署在Virtualbox上对其进行网络配置,选择连接方式为仅主机(Host-Only)网络。 2.配置kali的虚拟网络 在编辑中选择虚拟网络配…...

树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法
树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作,无需更改相机配置。但是,一…...

Day131 | 灵神 | 回溯算法 | 子集型 子集
Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣(LeetCode) 思路: 笔者写过很多次这道题了,不想写题解了,大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
JAVA后端开发——多租户
数据隔离是多租户系统中的核心概念,确保一个租户(在这个系统中可能是一个公司或一个独立的客户)的数据对其他租户是不可见的。在 RuoYi 框架(您当前项目所使用的基础框架)中,这通常是通过在数据表中增加一个…...

RSS 2025|从说明书学习复杂机器人操作任务:NUS邵林团队提出全新机器人装配技能学习框架Manual2Skill
视觉语言模型(Vision-Language Models, VLMs),为真实环境中的机器人操作任务提供了极具潜力的解决方案。 尽管 VLMs 取得了显著进展,机器人仍难以胜任复杂的长时程任务(如家具装配),主要受限于人…...

高考志愿填报管理系统---开发介绍
高考志愿填报管理系统是一款专为教育机构、学校和教师设计的学生信息管理和志愿填报辅助平台。系统基于Django框架开发,采用现代化的Web技术,为教育工作者提供高效、安全、便捷的学生管理解决方案。 ## 📋 系统概述 ### 🎯 系统定…...

【java面试】微服务篇
【java面试】微服务篇 一、总体框架二、Springcloud(一)Springcloud五大组件(二)服务注册和发现1、Eureka2、Nacos (三)负载均衡1、Ribbon负载均衡流程2、Ribbon负载均衡策略3、自定义负载均衡策略4、总结 …...

云原生时代的系统设计:架构转型的战略支点
📝个人主页🌹:一ge科研小菜鸡-CSDN博客 🌹🌹期待您的关注 🌹🌹 一、云原生的崛起:技术趋势与现实需求的交汇 随着企业业务的互联网化、全球化、智能化持续加深,传统的 I…...
OpenGL-什么是软OpenGL/软渲染/软光栅?
软OpenGL(Software OpenGL)或者软渲染指完全通过CPU模拟实现的OpenGL渲染方式(包括几何处理、光栅化、着色等),不依赖GPU硬件加速。这种模式通常性能较低,但兼容性极强,常用于不支持硬件加速…...

SFTrack:面向警务无人机的自适应多目标跟踪算法——突破小尺度高速运动目标的追踪瓶颈
【导读】 本文针对无人机(UAV)视频中目标尺寸小、运动快导致的多目标跟踪难题,提出一种更简单高效的方法。核心创新在于从低置信度检测启动跟踪(贴合无人机场景特性),并改进传统外观匹配算法以关联此类检测…...