当前位置: 首页 > news >正文

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

一、线程的描述&#xff1a; 1、线程是一个应用程序进程中不同的执行路径比例如&#xff1a;一个WEB服务器&#xff0c;能够为多个用户同时提供请求服务&#xff1b;而 -> 进程是操作系统中正在执行的不同的应用程序,比如&#xff1a;我们可以同时打开系统的word和游戏 2、多…...

PHP 判断用户当前坐标是否在电子围栏内

可以使用射线法判断用户当前坐标点是否在电子围栏内。 具体步骤如下&#xff1a; 1. 将电子围栏的四个角坐标按顺序连接成一个封闭多边形。 2. 从用户当前坐标点向外发射一条射线&#xff0c;判断这条射线与多边形的交点个数。 3. 如果交点个数为奇数&#xff0c;则用户当前…...

Java版本工程管理系统源码企业工程项目管理系统简介

一、立项管理 1、招标立项申请 功能点&#xff1a;招标类项目立项申请入口&#xff0c;用户可以保存为草稿&#xff0c;提交。 2、非招标立项申请 功能点&#xff1a;非招标立项申请入口、用户可以保存为草稿、提交。 3、采购立项列表 功能点&#xff1a;对草稿进行编辑&#x…...

高速缓存(cache)的原理: 了解计算机架构与性能优化

计基之存储器层次结构 Author&#xff1a; Once Day Date&#xff1a; 2023年5月9日 长路漫漫&#xff0c;而今才刚刚启程&#xff01; 本内容收集整理于《深入理解计算机系统》一书。 参看文档: 捋一捋Cache - 知乎 (zhihu.com)iCache和dCache一致性 - 知乎 (zhihu.com)C…...

【Vue3+TS项目】硅谷甄选day04--顶部组件搭建+面包屑+路由鉴权

顶部组件搭建 顶部左侧折叠和面包屑实现 左侧菜单刷新折叠的问题解决---属性default-active 折叠之后图标不见&#xff1a;icon放在插槽外面----element的menu属性&#xff1a;collapse project\src\layout\index.vue // 获取路由对象 import { useRoute } from vue-route…...

某oa 11.10 未授权任意文件上传

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

设计模式-行为型模式(模板方法、策略、观察者、迭代器、责任链、命令、状态、备忘录、访问者、中介者、解释器)

行为型模式&#xff1a;专注于对象之间的 协作 及如何通过彼此之间的交互来完成任务。行为型模式通常集中在描述对象之间的 责任 分配和 通信 机制&#xff0c;并提供了一些优雅解决特定问题的方案。 模板方法模式(Template Method Pattern)策略模式(Strategy Pattern)观察者模…...

全面探讨 Spring Boot 的自动装配机制

Spring Boot 是一个基于 Spring 框架的快速开发脚手架&#xff0c;它通过自动配置机制帮助我们快速搭建应用程序&#xff0c;从而减少了我们的配置量和开发成本。自动装配是 Spring Boot 的核心特点之一&#xff0c;它可以减少项目的依赖&#xff0c;简化配置文件&#xff0c;提…...

河道水位监测:河道水位监测用什么设备

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

嵌入式系统中u-boot和bootloader到底有什么区别

嵌入式软件工程师都听说过 u-boot 和 bootloader&#xff0c;但很多工程师依然不知道他们到底是啥。 今天就来简单讲讲 u-boot 和 bootloader 的内容以及区别。 Bootloader Bootloader从字面上来看就是启动加载的意思。用过电脑的都知道&#xff0c;windows开机时会首先加载…...

实验14:20211030 1+X 中级实操考试(id:2498)

实验14&#xff1a;20211030 1X 中级实操考试&#xff08;id&#xff1a;2498&#xff09; 一、项目背景说明二、表结构三、步骤【5 分】步骤 1&#xff1a;项目准备【5 分】步骤 2&#xff1a;完成实体类 Member【10 分】步骤 3&#xff1a;完成实体类 Goods【10 分】步骤 4&a…...

(字符串 ) 剑指 Offer 58 - II. 左旋转字符串 ——【Leetcode每日一题】

❓剑指 Offer 58 - II. 左旋转字符串 难度&#xff1a;简单 字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如&#xff0c;输入字符串"abcdefg"和数字2&#xff0c;该函数将返回左旋转两位得到的…...

EPICS编程

提纲 1&#xff09; 为什么在EPICS上编程 2&#xff09;构建系统特性&#xff1a;假设基本理解Unix Make 3&#xff09;在libCom中可用的工具 1&#xff09; 为什么在EPICS上编程 1、社区标准&#xff1a;EPICS合作者知道和明白EPICS结构 2、在很多操作系统之间代码移值性…...

17:00面试,还没10分钟就出来了,问的实在是太...

从外包出来&#xff0c;没想到死在另一家厂子 自从加入这家公司&#xff0c;每天都在加班&#xff0c;钱倒是给的不少&#xff0c;所以也就忍了。没想到8月一纸通知&#xff0c;所有人不许加班&#xff0c;薪资直降30%&#xff0c;顿时有吃不起饭的赶脚。 好在有个兄弟内推我去…...

docker都有那些工具,及工具面试题

docker介绍 Docker 是一种开源的容器化平台&#xff0c;可以帮助开发者将应用程序和依赖项打包到轻量级的容器中&#xff0c;然后部署到任何基于 Linux 的操作系统中。使用 Docker 可以大大简化开发、部署和管理应用程序的过程&#xff0c;使其更加快速、灵活和可靠。 Docker…...

LAMP网站应用架构

LAMP 一、LAMP概述1、各组件的主要作用2、构建LAMP各组件的安装顺序 二、编译安装Apache httpd服务1、关闭防火墙&#xff0c;将安装Apache所需软件包传到/opt目录下2.安装环境依赖包3.配置软件模块4.编译及安装5.优化配置文件路径&#xff0c;并把httpd服务的可执行程序文件放…...

C++虚函数virtual(动态多态)(纯虚函数)

怎么判断函数是虚函数还是普通函数&#xff1f; 用VS&#xff0c;在调用对象的方法的地方。。按altg &#xff0c;如果他跳转到正确的函数&#xff0c;那也就意味着他是编译时可以确定的。。。 但是如果他跳到了这个调用对象的基类的函数&#xff0c;那么也就意味着他是一个运行…...

【Java 接口】接口(Interface)的定义,implements关键字,接口实现方法案例

博主&#xff1a;_LJaXi Or 東方幻想郷 专栏&#xff1a; Java | 从入门到入坟 专属&#xff1a;六月一日 | 儿童节 Java 接口 接口简介 &#x1f383;接口的定义 &#x1f9e7;接口实现类名定义 &#x1f381;接口实现类小案例 &#x1f388;后话 &#x1f3b0; 接口简介 &…...

解决Vmware上的kali找不到virtualbox上的靶机的问题

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

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…...

理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端

&#x1f31f; 什么是 MCP&#xff1f; 模型控制协议 (MCP) 是一种创新的协议&#xff0c;旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议&#xff0c;它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...

dedecms 织梦自定义表单留言增加ajax验证码功能

增加ajax功能模块&#xff0c;用户不点击提交按钮&#xff0c;只要输入框失去焦点&#xff0c;就会提前提示验证码是否正确。 一&#xff0c;模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...

Python实现prophet 理论及参数优化

文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候&#xff0c;写过一篇简单实现&#xff0c;后期随着对该模型的深入研究&#xff0c;本次记录涉及到prophet 的公式以及参数调优&#xff0c;从公式可以更直观…...

论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)

宇树机器人多姿态起立控制强化学习框架论文解析 论文解读&#xff1a;交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架&#xff08;一&#xff09; 论文解读&#xff1a;交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...

ElasticSearch搜索引擎之倒排索引及其底层算法

文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...

RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程

本文较长&#xff0c;建议点赞收藏&#xff0c;以免遗失。更多AI大模型应用开发学习视频及资料&#xff0c;尽在聚客AI学院。 本文全面剖析RNN核心原理&#xff0c;深入讲解梯度消失/爆炸问题&#xff0c;并通过LSTM/GRU结构实现解决方案&#xff0c;提供时间序列预测和文本生成…...

智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制

在数字化浪潮席卷全球的今天&#xff0c;数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具&#xff0c;在大规模数据获取中发挥着关键作用。然而&#xff0c;传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时&#xff0c;常出现数据质…...

Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习)

Aspose.PDF 限制绕过方案&#xff1a;Java 字节码技术实战分享&#xff08;仅供学习&#xff09; 一、Aspose.PDF 简介二、说明&#xff08;⚠️仅供学习与研究使用&#xff09;三、技术流程总览四、准备工作1. 下载 Jar 包2. Maven 项目依赖配置 五、字节码修改实现代码&#…...

【分享】推荐一些办公小工具

1、PDF 在线转换 https://smallpdf.com/cn/pdf-tools 推荐理由&#xff1a;大部分的转换软件需要收费&#xff0c;要么功能不齐全&#xff0c;而开会员又用不了几次浪费钱&#xff0c;借用别人的又不安全。 这个网站它不需要登录或下载安装。而且提供的免费功能就能满足日常…...