JUC并发编程之基础回顾第一篇

一、集合类

(一)ArrayList

1、看底层源代码

  • new了一个Object数组
    在这里插入图片描述

  • 默认初始为new Object[10]
    在这里插入图片描述
    在这里插入图片描述
    但是如果你什么都没有传入的情况下是不会先创建数组的,只有在你添加了第一条数据的时候才会被创建出来数组
    在这里插入图片描述

  • 当我们有25个数据怎么办呢?
    答案是跟随你原来的值+ 原来的值除2【比如10 --> 15 ,15–>22,22–> 33】
    在这里插入图片描述
    在这里插入图片描述

  • 可以观察源代码发现它的方法都没有通过synchronized来修饰方法或者类,所以它不是线程安全的。

2、线程不安全

  • 演示线程不安全【会发现我们明明是应该放三个,但是却就放了两个,你多执行两次就会发现】
    在这里插入图片描述
  • 再演示报错情况:java.util.ConcurrentModificationException
    在这里插入图片描述
    在这里插入图片描述
  • 上面解决办法

(1)使用Vector

第一种想法【这种不建议因为synchronized锁住了整张表,并发性就下降,性能不行】
在这里插入图片描述
在这里插入图片描述

(2)使用的Collections的synchronizedList方法

- 使用Collections接口的类

在这里插入图片描述

(3)第三种方法CopyOnWriteArrayList

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

咱不能只做api调用工程师,所以去看看底层

  • CopyOnWriteArrayList【【写时复制技术】是读写思想分离的体现】
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

(二)Set

1、看看set源代码

在这里插入图片描述
在这里插入图片描述

  • 底层采用的什么数据结构:答案是HashMap<E,Object>
    在这里插入图片描述

  • 添加一个数据的时候是什么情况呢
    在这里插入图片描述
    在这里插入图片描述

  • set也是不安全的:可以看到源代码并没有定义为安全的

2、解决办法

  • 也是采用写时复制技术
    在这里插入图片描述

(三)Map

1、看源代码

在这里插入图片描述
其实都差不多的,可以自己去点源代码看看

2、解决办法

  • 处理为ConcurrentHashMap
    在这里插入图片描述

二、java锁

(一)八个锁

  • 线程 --------操作 --------资源类

1、标准访问看看谁先打印

(1)看代码和结果

package cn.mldn.Juc.class2;

class Phone {
    public synchronized void wangzry() throws Exception {
        System.out.println("打开王者荣耀");
    }
    public synchronized void juedqs() throws Exception {
        System.out.println("打开绝地求生");
    }

    public synchronized void baid() throws Exception {
        System.out.println("打开了百度");
    }
}


public class LockTest {

    public static void main(String[] args) {

        //1、资源类
        Phone phone = new Phone();

        new Thread(() -> {
            try {
                phone.wangzry();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"线程A");

        new Thread(() -> {
            try {
                phone.juedqs();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"线程B");

        new Thread(() -> {
            try {
                phone.baid();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"线程C");
    }

}

  • 这种情况的结果【一般情况下会是这个,但是要知道出现这个答案是偶然的,并不是绝对的,但是一般情况下你写的顺序,被加载的顺序的原因,执行顺序就是从上往下进行执行,首先A被调度,然后到B,然后到C】
    在这里插入图片描述

(2)结果分析

在这里插入图片描述
创建线程A后,只要你访问的是synchronized标注的方法,那么这个类对象都会被锁住(它的性能就下降了),所以我A只要锁住了,后续的向要进行操作的就要乖乖排队。

2、加个sleep看看

(1)看代码和结果

package cn.mldn.Juc.class2;

import java.util.concurrent.TimeUnit;

class Phone {
    public synchronized void wangzry() throws Exception {
        try {
            Thread.sleep(4000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("打开王者荣耀");
    }
    public synchronized void juedqs() throws Exception {
        System.out.println("打开绝地求生");
    }

}


public class LockTest {

    public static void main(String[] args) {

        //1、资源类
        Phone phone = new Phone();




        new Thread(() -> {
            try {
                phone.wangzry();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"线程A").start();


        new Thread(() -> {
            try {
                phone.juedqs();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"线程B").start();


    }


}


  • 看结果
    在这里插入图片描述

(2)结果分析

原因其实是一样的,我的A线程根据顺序得到先被加载,然后它会把整个对象锁起来,然后进行它的操作。
在这里插入图片描述

(3)对1和2进行分析

它们两个锁的是this,锁的是当前对象,并不是同时进来,各回各家,各找各妈的,而是A先占用了,那么B就要等着,等我A用完了,你再用。
在这里插入图片描述

3、加另外一个sleep看看

package cn.mldn.Juc.class2;


class Phone {
    public synchronized void wangzry() throws Exception {
        System.out.println("打开王者荣耀");
    }
    public synchronized void juedqs() throws Exception {

        System.out.println("打开绝地求生");
    }

    public synchronized void baid() throws Exception {
        System.out.println("打开了百度");
    }
}


public class LockTest {

    public static void main(String[] args) {

        //1、资源类
        Phone phone = new Phone();



        new Thread(() -> {
            try {
                phone.wangzry();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"线程A").start();

        new Thread(() -> {
            try {
                phone.wangzry();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"线程B").start();


        try {
            Thread.sleep(4000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        new Thread(() -> {
            try {
                phone.baid();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"线程C").start();
    }


}

在这里插入图片描述

4、加个普通方法看看

(1)看代码和结果

package cn.mldn.Juc.class2;

import java.util.concurrent.TimeUnit;

class Phone {
    public synchronized void wangzry() throws Exception {
        TimeUnit.SECONDS.sleep(4);
        System.out.println("打开王者荣耀");
    }

    public synchronized  void baid() throws Exception {
        System.out.println("打开了百度");
    }

    public void sayHello() throws Exception {
        System.out.println("SayHello");
    }
}


public class LockTest {

    public static void main(String[] args) {

        //1、资源类
        Phone phone = new Phone();



            new Thread(() -> {
                try {
                    phone.wangzry();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            },"线程A").start();


           /* new Thread(() -> {
                try {
                    phone.baid();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            },"线程C").start();*/

        new Thread(() -> {
            try {
                phone.sayHello();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"线程D").start();
        }


}
  • 看看结果
    在这里插入图片描述

(2)结果分析

为什么我们的SayHello方法进去就打印了呢?
原因其实你虽然对和那些方法是没什么关系的,你该调则调。它们之间没什么冲突。【一定要注意它是同一个资源,即同一个对象】

5、打开两部手机

(1)看代码和结果分析

  • 看代码
package cn.mldn.Juc.class2;

import java.util.concurrent.TimeUnit;

class Phone {
    public synchronized void wangzry() throws Exception {
        TimeUnit.SECONDS.sleep(4);
        System.out.println("打开王者荣耀");
    }

    public synchronized  void baid() throws Exception {
        System.out.println("打开了百度");
    }

    public void sayHello() throws Exception {
        System.out.println("SayHello");
    }
}


public class LockTest {

    public static void main(String[] args) {

        //1、资源类
        Phone phone = new Phone();
        Phone phone1 = new Phone();


        //2、操作资源
        new Thread(() -> {
            try {
                phone.wangzry();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"线程A").start();


        new Thread(() -> {
            try {
                phone1.baid();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"线程B").start();

    }
}

  • 结果
    在这里插入图片描述

(2)结果分析

此时不存在争取的问题,是存在各自回家的样子了。两个都不是同一把锁的了,根本不会冲突了。

6、两个静态方法(一部手机)

(1)看代码和结果

package cn.mldn.Juc.class2;

import java.util.concurrent.TimeUnit;

class Phone {
    public static synchronized void wangzry() throws Exception {
        TimeUnit.SECONDS.sleep(4);
        System.out.println("打开王者荣耀");
    }

    public static synchronized  void baid() throws Exception {
        System.out.println("打开了百度");
    }

}


public class LockTest {

    public static void main(String[] args) {

        //1、资源类
        Phone phone = new Phone();



        //2、操作资源
        new Thread(() -> {
            try {
                phone.wangzry();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"线程A").start();


        new Thread(() -> {
            try {
                phone.baid();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"线程B").start();

    }
}

  • 看结果
    在这里插入图片描述

(2)结果分析

其实就和加不加没什么区别的吧,但是有很大的区别。

  • 被static的方法加上一个synchronized之后,它是属于当前类的模板部分。它是把你的整个类锁了,【这就是对象锁和全局锁(这么一个类)的一个区别,static锁的全局,对象锁去哪个就是哪个对象】

(3)对象锁和类型锁

  • 不加static的情况下,我们的两步手机是没什么影响的,锁的是对象。但是如果加了锁的就是当前类了。
  • 看如下的代码
class Phone {
    public static synchronized void wangzry() throws Exception {
        TimeUnit.SECONDS.sleep(4);
        System.out.println("打开王者荣耀");
    }

    public static synchronized  void baid() throws Exception {
        System.out.println("打开了百度");
    }

    public  void sayHello() throws Exception {
        System.out.println("sayHello");
    }

}


public class LockTest {

    public static void main(String[] args) {

        //1、资源类
        Phone phone = new Phone();
        Phone phone1 = new Phone();



        //2、操作资源
        new Thread(() -> {
            try {
                phone.wangzry();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"线程A").start();


        new Thread(() -> {
            try {
                phone1.baid();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"线程B").start();


        new Thread(() -> {
            try {
                phone.sayHello();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"线程C").start();
    }
}
  • 总结:对于普通的同步方法锁的是当前对象【synchronized(this)一样的】。而对于static是锁的类型了。其实加上了static就相当于锁住当前类型。

7、两部手机实现第六步

(1)看代码和结果

package cn.mldn.Juc.class2;

import java.util.concurrent.TimeUnit;

class Phone {
    public static synchronized void wangzry() throws Exception {
        TimeUnit.SECONDS.sleep(4);
        System.out.println("打开王者荣耀");
    }

    public static synchronized  void baid() throws Exception {
        System.out.println("打开了百度");
    }

}


public class LockTest {

    public static void main(String[] args) {

        //1、资源类
        Phone phone = new Phone();



        //2、操作资源
        new Thread(() -> {
            try {
                phone.wangzry();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"线程A").start();


        new Thread(() -> {
            try {
                phone.baid();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"线程B").start();

    }
}

  • 答案是和上一步分析是一样的
    在这里插入图片描述

8、一个静态同步方法,一个普通同步方法,同一部手机

(1)看代码和结果

package cn.mldn.Juc.class2;

import java.util.concurrent.TimeUnit;

class Phone {
    public static synchronized void wangzry() throws Exception {
        TimeUnit.SECONDS.sleep(4);
        System.out.println("打开王者荣耀");
    }

    public synchronized  void baid() throws Exception {
        System.out.println("打开了百度");
    }

}


public class LockTest {

    public static void main(String[] args) {

        //1、资源类
        Phone phone = new Phone();




        //2、操作资源
        new Thread(() -> {
            try {
                phone.wangzry();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"线程A").start();


        new Thread(() -> {
            try {
                phone.baid();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"线程B").start();

    }
}

  • 看结果
    在这里插入图片描述

(2)分析

他们两个是互相不冲突的。普通方法锁的是当前对象。

9、两部手机完成上面

(1)看代码和结果

  • 看代码
package cn.mldn.Juc.class2;

import java.util.concurrent.TimeUnit;

class Phone {
    public static synchronized void wangzry() throws Exception {
        TimeUnit.SECONDS.sleep(4);
        System.out.println("打开王者荣耀");
    }

    public synchronized  void baid() throws Exception {
        System.out.println("打开了百度");
    }

}


public class LockTest {

    public static void main(String[] args) {

        //1、资源类
        Phone phone = new Phone();
        Phone phone2 = new Phone();




        //2、操作资源
        new Thread(() -> {
            try {
                phone.wangzry();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"线程A").start();


        new Thread(() -> {
            try {
                phone2.baid();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"线程B").start();

    }
}

  • 看结果
    在这里插入图片描述

(2)结果分析

这个不用分析了吧,比较简单了。

10、小总结

在这里插入图片描述

(二)生产者–消费者

1)消费者上【传统版本】

1、代码实现(第一个版本)

package cn.mldn.Juc.producerAndcustomer;

class Message1 {
    private int number = 0;

    public synchronized void Producer() {
        //1判断
        if (number != 0) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //2生产
        number++;
        System.out.println("当前线程" + Thread.currentThread().getName()+ "完成工作" + number);
        //3通知
        this.notify();
    }

    public synchronized void Consumer() {

        //1判断
        if (number != 1) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //2消费
        number--;
        System.out.println("当前线程" + Thread.currentThread().getName()+ "完成工作" + number);
        //3通知
        this.notify();
    }
}


public class mainClass1 {

    public static void main(String[] args) {
        Message1 message = new Message1();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                message.Producer();
            }
        },"线程A").start();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                message.Producer();
            }
        },"线程B").start();
    }
}

2、第二种版本(有问题)

package cn.mldn.Juc.producerAndcustomer;

class Message1 {
    private int number = 0;

    public synchronized void Producer() {
        //1判断
        if (number != 0) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //2生产
        number++;
        System.out.println("当前线程" + Thread.currentThread().getName()+ "完成工作" + number);
        //3通知
        this.notify();
    }

    public synchronized void Consumer() {

        //1判断
        if (number != 1) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //2消费
        number--;
        System.out.println("当前线程" + Thread.currentThread().getName()+ "完成工作" + number);
        //3通知
        this.notify();
    }
}


public class mainClass1 {

    public static void main(String[] args) {
        Message1 message = new Message1();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                message.Producer();
            }
        },"线程A").start();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                message.Producer();
            }
        },"线程B").start();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                message.Consumer();
            }
        },"线程C").start();

		new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                message.Consumer();
            }
        },"消费线程D").start();
    }
}

3、第二个版本的解决办法

class Message1 {
    private int number = 0;

    public synchronized void Producer() {
        //1判断
        while (number != 0) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //2生产
        number++;
        System.out.println("当前线程" + Thread.currentThread().getName()+ "完成工作" + number);
        //3通知
        this.notifyAll();
    }

    public synchronized void Consumer() {

        //1判断
        while (number != 1) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //2消费
        number--;
        System.out.println("当前线程" + Thread.currentThread().getName()+ "完成工作" + number);
        //3通知
        this.notifyAll();
    }
}


public class mainClass1 {

    public static void main(String[] args) {
        Message1 message = new Message1();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                message.Producer();
            }
        },"生产线程A").start();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                message.Producer();
            }
        },"生产线程B").start();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                message.Consumer();
            }
        },"消费线程C").start();

		 new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                message.Consumer();
            }
        },"消费线程D").start();
    }
}

为什么呢?其实我们的while本质是循环加判断。所以它可以判断,而且当你通过了,还要拉回来重新判断。

4、到这里的一个小总结

我们在第(一)中已经完成了高内聚低耦合下,线程操作资源类
第(二)完成了判断,干活,通知的处理,在第(二)步骤的3步完成了防止了虚假唤醒。

5、第2步的问题分析

为什么用if判断,用两个线程就没问题了呢,四个就出问题了呢

  • 其实很好理解:两个线程,就你跟我,你生产我消费,你生产了,就叫我去消费,我消费了就叫你生产。但是四个来就不好理解了,A和B生产,C和D消费,如果通知生产,A和B同时生成。那就出现了2的情况了。
  • 四个的情况:用了while后,为什么就可以了?其实也比较好理解,while的本质是循环加判断。我判断你了,还要把你循环拉回来再判断。

2)消费者线程下【Lock版本】

  • 多线程套路为多线程格式+while判断。

  • Lock(可重复的可递归的非公平的锁)
    在这里插入图片描述

1、存在问题版本

package cn.mldn.Juc.producerAndcustomer;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class Message1 {
    private int number = 0;
    private Lock lock = new ReentrantLock();

    public void Producer() {
        //1判断
        lock.lock();
        try {
            while (number != 0) {
                try {
                        this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

        //2生产
        number++;
        System.out.println("当前线程" + Thread.currentThread().getName()+ "完成工作" + number);
        //3通知
        this.notifyAll();
    }

    public void Consumer() {

        //1判断
        lock.lock();
        try {
            while (number != 1) {
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
        //2消费
        number--;
        System.out.println("当前线程" + Thread.currentThread().getName()+ "完成工作" + number);
        //3通知
        this.notifyAll();
    }

}


public class mainClass1 {

    public static void main(String[] args) {
        Message1 message = new Message1();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                message.Producer();
            }
        },"生产线程A").start();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                message.Producer();
            }
        },"生产线程B").start();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                message.Consumer();
            }
        },"消费线程C").start();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                message.Consumer();
            }
        },"消费线程D").start();
    }
}

在这里插入图片描述
我们之前的唤醒和休眠,用的方法不行,报错了。接下来用lock的解决。

2、解决办法

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

package cn.mldn.Juc.producerAndcustomer;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class Message1 {
    private int number = 0;
    private Lock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();
    public void Producer() {
        //1判断
        lock.lock();
        try {
            while (number != 0) {
                try {
                        condition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            //2生产
            number++;
            System.out.println("当前线程" + Thread.currentThread().getName()+ "完成工作" + number);
            //3通知
            condition.signalAll();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }


    }

    public void Consumer() {

        //1判断
        lock.lock();
        try {
            while (number != 1) {
                try {
                    condition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            //2消费
            number--;
            System.out.println("当前线程" + Thread.currentThread().getName()+ "完成工作" + number);
            //3通知
            condition.signalAll();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

    }

}


public class mainClass1 {

    public static void main(String[] args) {
        Message1 message = new Message1();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                message.Producer();
            }
        },"生产线程A").start();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                message.Producer();
            }
        },"生产线程B").start();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                message.Consumer();
            }
        },"消费线程C").start();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                message.Consumer();
            }
        },"消费线程D").start();
    }
}

3、ConditionDemo(为了解决多线程间按顺序调用A-B-C)

在这里插入图片描述

package cn.mldn.Juc.producerAndcustomer;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class ShareDate {
    //标志位为1,A:打印 2:B打印,3:C打印
    private int number = 1;
    private Lock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();
    private Condition condition1 = lock.newCondition();
    private Condition condition2 = lock.newCondition();

    public void print5() {
        lock.lock();
        try {
            //1判断
            while (number != 1) {
                condition.await();
            }
            //2A干活打印5次
            for (int i = 0; i < 5; i++) {
                System.out.println("" + Thread.currentThread().getName() + i);
            }
            //3通知(现在是通知某一个吧)
            number = 2;
            condition.signal();

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void print10() {
        lock.lock();
        try {
            //1判断
            while (number != 2) {
                condition1.await();
            }
            //2A干活打印5次
            for (int i = 0; i < 5; i++) {
                System.out.println("" + Thread.currentThread().getName() + i);
            }
            //3通知(现在是通知某一个吧)
            number = 3;
            condition2.signal();

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void print15() {
        lock.lock();
        try {
            //1判断
            while (number != 3) {
                condition2.await();
            }
            //2A干活打印5次
            for (int i = 0; i < 5; i++) {
                System.out.println("" + Thread.currentThread().getName() + i);
            }
            //3通知(现在是通知某一个吧)
            number = 3;
            condition.signal();

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

}

public class ConditionDemo {

    public static void main(String[] args) {
        ShareDate shareDate = new ShareDate();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                shareDate.print5();
            }
        },"线程A").start();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                shareDate.print10();
            }
        },"线程B").start();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                shareDate.print15();
            }
        },"线程C").start();
    }
}

一个锁配置了三把钥匙进行精确打击处理。

三、Callable实现多线程

  • 我们之前学习过了Runnable和Thread实现多线程,其实有三种可以实现多线程的方法(后续还会有一种)。【其实和Runnabl差不多的,它的最大的区别就是Callable有返回值(另外它还有区别,它还有异常)】

1、看源代码

在这里插入图片描述
这个call方法和run差不多的。而且看注解和只有一个方法,那可以用Lambda表达式。

2、如何实现启动

  • 看到这个
    在这里插入图片描述
  • 我们用FutureTask(后面的SwingWorker不用,它不会用)
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

通过继承关系,就可以发现最终我们传递的就是一个Runnable接口的子接口吧。

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

class CallableMessage implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {
        System.out.println(1+1+1+1+1+1+1+1);
        return 1+1+1+1+1+1+1+1;
    }
}

public class CallableTest {

    public static void main(String[] args) {

        FutureTask futureTask = new FutureTask(new CallableMessage());

        new Thread(futureTask,"线程A").start();

    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值