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()方法
    @Override
    public 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()方法
    @Override
    public 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> {

    @Override
    public 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() {
            @Override
            public 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 {

    @Override
    public 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 {

    @Override
    public 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 {

    @Override
    public 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);//1
        thread1.setPriority(Thread.NORM_PRIORITY);//5
        thread2.setPriority(Thread.MAX_PRIORITY);//10
        thread3.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 {

    @Override
    public void run() {
        // 验证虚拟机不用等待守护线程执行完毕,只要用户线程执行完毕,程序就结束。
        while (true){
            System.out.println("守护线程");
        }
    }
}
//用户进程
class UserThread implements Runnable{

    @Override
    public void run() {
        for (int i =0 ;i<2;i++) {
            System.out.println("用户线程:" + i);
        }
    }
}

isAlive方法:

        -用于检查线程是否处于活动状态。活着是指已开始但尚未终止的线程。调用run方法时,线程将运行特定的时间段,然后停止执行。
public class JavaStudyThread implements Runnable {
    @Override
    public 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函数已被调用
        sample
        only
        only
    */
}

六、多线程 并发 和 同步: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() {
            @Override
            public 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;
    }

    @Override
    public 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;
    }

    @Override
    public 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();

    @Override
    public 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());

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>