多线程(JavaEE初阶系列4)

这篇具有很好参考价值的文章主要介绍了多线程(JavaEE初阶系列4)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

前言:

1.单例模式

1.1饿汉模式

1.2懒汉模式

1.3结合线程安全下的单例模式

1.4单例模式总结

2.阻塞式队列

2.1什么是阻塞队列

2.2生产者消费者模型

2.2.1 上下游模块之间进行“解耦合”

2.2.2削峰填谷

2.3阻塞队列的实现

结束语:


前言:

在上节中小编主要与大家分享了多线程中遇到的不安全问题以及如何进行解决,那么这节中小编与大家讲解一下在多线程中的案例,在次之前我们先来了解一下什么是设计模式?设计模式就好比象棋中的“棋谱”,在下棋的时候前人总结的一些固定套路,如果我们按照套路来走局势就不会太吃亏。在软件开发中也有很多常见的“问题场景”,针对这些问题场景,大佬们总结出了一些固定的套路,按照这个套路来实现代码就不会太吃亏。在多线程中的设计模式有很多,但是尤为经典的还是单例模式和阻塞式队列这两个,所以今天小编就与大家聊聊这两个模式。

1.单例模式

单例模式能保证在某个类在程序中只存在一份实例,而不会创建出多个实例。在单例模式中具体的实现方法有两种“饿汉”和“懒汉”两种。下面就给大家分别展开聊聊这两种。

1.1饿汉模式

饿汉你可以理解为“急迫”,可以以生活中吃完饭洗碗来举个例子,如果你吃完饭就把碗洗了此时就是比较“急迫”,就是一种饿汉行为。对应在我们的计算机中如果打开硬盘上的文件,读取文件的内容,并显示内容的话,饿汉模式下就是把文件中所有的内容都读取到内存中,并显示出来。

代码展示:

package Thread;
//将这个类设置成单例的
class Singleton{
    //唯一实例的本体
    //这里Singleton被static修饰表示该属性是类的属性
    //JVM中每个类的类对象只有唯一一份,类对象里的这个成员也就自然只有唯一一份了
    private static Singleton instance = new Singleton();

    //获取到实例的方法
    public static Singleton getInstance() {
        return instance;
    }

    //禁止外部new实例,将构造方法设为私有的
    private Singleton() {

    }
}
public class ThreadDemo21 {
    public static void main(String[] args) {
        //此时 s1 和 s2是同一个对象!!!
        Singleton s1 = Singleton.getInstance();
        Singleton s2 = Singleton.getInstance();
//        Singleton s3 = new Singleton();
        System.out.println(s1 == s2);
    }
}

结果展示:
多线程(JavaEE初阶系列4),JavaEE初阶,java-ee,java注意:

  • 我们是直接在类内就将实体定义好了,并且是由static来修饰的,这样就保证了该属性是类的属性,而且只要一份。
  • 我们要想在类外禁止掉新创建实体,那么我们就需要在类内将构造方法设置为私有的,这样就可以保证我们在类外不能创建实体了。
  • 这里可能就有同学好奇了,那么private修饰了构造方法,那么为什么上面可以创建一个实体而在主函数中就不可以创建了呢?还记得private的范围吗?由private修饰是不可以在类外访问而类内还是可以访问到的。这里大家一定要注意。
  • 我们在上述代码的结果中可以看到通过类来创建的两个对象其实指向的都是同一个空间,也就相当于是同一个对象了。

1.2懒汉模式

根据上面对饿汉模式的讲解相信大家对懒汉模式也大体有一个概念了,懒汉模式可以理解为“从容”,就是饿汉模式的反例,拿上述洗碗来举例子就是吃完饭之后不洗碗,等到下一次吃饭的时候在洗碗,对应到计算机中的那个读取文件内容的例子来说就是只读取文件中的一小部分,把当前屏幕填充上,如果用户翻页了,在读取其他文件的内容,如果不翻页就省下来了。

其实相比较上述的饿汉模式来说,懒汉模式的效率是比饿汉模式的效率高的。

下面我们用懒汉模式来给大家实现一下单例。

代码展示:

package Thread;
//通过懒汉模式来实现单例模式
class SingletonLazy{
    private static SingletonLazy instance = null;
    public static SingletonLazy getInstance() {
        if (instance == null) {
            instance = new SingletonLazy();
        }
        return instance;
    }
    //禁止类外创建实体
    private SingletonLazy() {

    }
}
public class ThreadDemo22 {
    public static void main(String[] args) {
        SingletonLazy s1 = SingletonLazy.getInstance();
        SingletonLazy s2 = SingletonLazy.getInstance();
        System.out.println(s1 == s2);
    }
}


结果展示:
多线程(JavaEE初阶系列4),JavaEE初阶,java-ee,java

相比上述的饿汉模式来说,懒汉模式其实就是在创建实体的时候作出了变动,在饿汉模式中是直接创建出了一个实体,而在懒汉模式中则是先查看有没有该对象的实体,如果有就不创建了,如果没有再去创建一个实体。

1.3结合线程安全下的单例模式

在上述中给大家简单的交代了什么是饿汉模式什么是懒汉模式,以及分别给大家用代码来实现了一下,接下来我们就结合这上节中给大家讲解的线程安全,来让单例模式也变得安全起来。如果没有查看线程安全的同学记得先查看一下线程安全这节博客哦!(http://t.csdn.cn/L0JJ6)

首先我们先来看饿汉模式。

多线程(JavaEE初阶系列4),JavaEE初阶,java-ee,java

在饿汉模式中我们就只涉及到了读操作,所以它本身就是线程安全的,不需要修改。

下面看一下懒汉模式。

多线程(JavaEE初阶系列4),JavaEE初阶,java-ee,java

那么在懒汉模式中我们涉及到了一步判断,在执行判断的时候,如果是在多线程的情况下可能就处于一种不安全的状态了,如下所示:

多线程(JavaEE初阶系列4),JavaEE初阶,java-ee,java

如果t1和t2线程是按照上述的顺序执行的,当t1进入判断的时候是null的,此时当t2也进入判断的时候发现也是空的,那么在t1创建完实体之后,t2也会创建一个实体,此时不就多创建出来一个实体吗?这就与我们之前的预期结果不符了,就出现bug了。所以此时的线程是不安全的。那么在上节中我们出现这种问题是如何解决的呢?那当然是给线程加锁了。我们直接给类对象加锁,这样就可以保证判定和new是一个原子操作了。

如下所示:

多线程(JavaEE初阶系列4),JavaEE初阶,java-ee,java

但是加锁其实是一个低效的操作,我们在一般情况下是“非必要,不加锁”,因为加锁就有可能涉及到阻塞等待。

在上述代码中任何情况下调用getInstance都会出发锁的竞争。

其实这里的线程不安全只会出现在第一次创建对象这里,一旦对象new好之后,后续调用getInstance就只是单纯的读操作,就没有线程不安全问题了,也就没必要加锁了。

所以改进之后,如下面的代码所示:
多线程(JavaEE初阶系列4),JavaEE初阶,java-ee,java

解决了上述线程不安全的问题之后,我们还要注意一个很重要的问题就是指令重排序的问题。

假设两个线程同时调用getInstance的时候,就有可能出发指令重排序的问题。指令重排序的时候会有三步:

  1. 创建内存。
  2. 调用构造方法。
  3. 把内存地址赋给引用。

 其中的2 和 3 是可以随意调用的,顺序是可以颠倒的。

这里可以给大家举一个例子。在买房子的时候,我们是先看好房子之后,交首付,然后商家给你钥匙,此时你拿到的就是一个毛坯房,你自己去装修,亦或者是,商家已经将房子装修好了,直接给你钥匙,此时你拿到的就是一个精修房。

类比到我们计算机中就是创建内存就是买房子的操作,调用构造方法你可以想象成是装修房子,把内存赋给引用就是拿到了房子的钥匙

所以如果t1在执行完创建内存后先执行的是将内存赋给引用,此时系统调度给了t2了,然后t2进入if语句判断的时候发现是非空的,就直接返回t1的那个引用了,此时t2就相当于拿到的是一个毛坯房,接下来t2在调用里面的构造方法啥的可能就会出现一系列的问题!!!

此时我们就需要用到上节博客中给大家提到的防止指令重排序的一个关键字volatile,使用他我们就可以使得指令禁止重排序了。如下所示: 

多线程(JavaEE初阶系列4),JavaEE初阶,java-ee,java

代码整体展示:

package Thread;
//通过懒汉模式来实现单例模式
class SingletonLazy{
    //加关键字volatile 禁止指令重排序。
    volatile private static SingletonLazy instance = null;
    public static SingletonLazy getInstance() {
        //这个条件是判断是否要加锁,如果对象已经有了,就不必在加锁,此时本身线程就是安全的。
        if (instance == null) {
            //加锁
            synchronized (SingletonLazy.class) {
                if (instance == null) {
                    instance = new SingletonLazy();
                }
            }
        }
        return instance;
    }
    //禁止类外创建实体
    private SingletonLazy() { }
}
public class ThreadDemo22 {
    public static void main(String[] args) {
        SingletonLazy s1 = SingletonLazy.getInstance();
        SingletonLazy s2 = SingletonLazy.getInstance();
        System.out.println(s1 == s2);
    }
}

1.4单例模式总结

单例模式的实现有饿汉模式和懒汉模式,同时单例模式下会存在线程安全问题。

饿汉模式:天然就是安全的,只是涉及到了读操作。

懒汉模式:不安全的,有读也有写,所以为了解决它我们分为了三步。

  1. 加锁:把if和new变成原子操作。
  2. 双重if,减少不必要的加锁操作。
  3. 使用volatile禁止指令重排序,保证后续的线程肯定拿到的是一个完整的对象。

2.阻塞式队列

2.1什么是阻塞队列

队列在之前的数据结构中大家都有了解过,就是一种先进先出的结构。阻塞队列是一种特殊的队列,也遵守着“先进先出”的原则。

阻塞队列是一种线程安全的数据结构,并且具有以下特性:

  • 如果队列空,尝试出队列,就会阻塞等待,等待队列不空为止。
  • 如果队列满,尝试入队列,就会阻塞等待,等待队列不满为止。

先来给大家介绍一下阻塞队列中的两个核心方法:
代码展示:

package Thread;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;

public class ThreadDemo23 {
    public static void main(String[] args) throws InterruptedException {
        //这里的BlockingDeque是一个接口所以在实例化的时候我们使用的是以下两种形式
        //可以是数组形式的
//        BlockingDeque<String> queue = new ArrayBlockingQueue<>();
        //也可以使用的是链的形式
        BlockingDeque<String> queue = new LinkedBlockingDeque<>();
        //阻塞队列的核心方法,主要有两个
        //1.put入队列
        queue.put("hello1");
        queue.put("hello2");
        queue.put("hello3");
        queue.put("hello4");
        queue.put("hello5");

        //2.take出队列
        String result = null;
        result = queue.take();
        System.out.println(result);

        result = queue.take();
        System.out.println(result);

        result = queue.take();
        System.out.println(result);

        result = queue.take();
        System.out.println(result);

        result = queue.take();
        System.out.println(result);
    }
}


结果展示:
多线程(JavaEE初阶系列4),JavaEE初阶,java-ee,java

上述是执行了5次put操作5次take操作。发现一切都是正常的,但是如果我们执行5次put操作,6次take操作呢?如下代码所示:
代码展示:

package Thread;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;

public class ThreadDemo23 {
    public static void main(String[] args) throws InterruptedException {
        //这里的BlockingDeque是一个接口所以在实例化的时候我们使用的是以下两种形式
        //可以是数组形式的
//        BlockingDeque<String> queue = new ArrayBlockingQueue<>();
        //也可以使用的是链的形式
        BlockingDeque<String> queue = new LinkedBlockingDeque<>();
        //阻塞队列的核心方法,主要有两个
        //1.put入队列
        //第一次put操作
        queue.put("hello1");
        //第二次put操作
        queue.put("hello2");
        //第三次put操作
        queue.put("hello3");
        //第四次put操作
        queue.put("hello4");
        //第五次put操作
        queue.put("hello5");

        //2.take出队列
        String result = null;
        //第一次take操作
        result = queue.take();
        System.out.println(result);
        //第二次take操作
        result = queue.take();
        System.out.println(result);
        //第三次take操作
        result = queue.take();
        System.out.println(result);
        //第四次take操作
        result = queue.take();
        System.out.println(result);
        //第五次take操作
        result = queue.take();
        System.out.println(result);
        //第六次take操作
        result = queue.take();
        System.out.println(result);
    }
}


结果展示:

多线程(JavaEE初阶系列4),JavaEE初阶,java-ee,java
jconsole所示:

多线程(JavaEE初阶系列4),JavaEE初阶,java-ee,java

可以通过结果或者是直接通过jconsole来看到线程是处于一个阻塞状态的!!!

2.2生产者消费者模型

在阻塞队列中一个典型的应用场景就是“生产者消费者模型”,这是一种典型的开发模型。

这里给大家举一个例子:
包饺子的场景。

包法1:每一个滑稽老铁,自己擀一个饺子皮,自己包一个饺子,在擀一个饺子皮,在包一个饺子。

多线程(JavaEE初阶系列4),JavaEE初阶,java-ee,java

虽然上述做法,确实是每一个滑稽都包饺子了,但是如果有一个擀面杖的话这个效率显然就很低!这就相当于四个滑稽老铁需要同时竞争一个擀面杖。所以我们更常见的包法是第二种包法,流水线的包法。 

包法2:一个滑稽负责擀饺子皮,另外三个负责包饺子。

多线程(JavaEE初阶系列4),JavaEE初阶,java-ee,java

上述情况下就构成了生产者和消费者模型,对于饺子皮来说, A滑稽就是一个生产者,他负责生产饺子皮,而B、C、D滑稽就是消费者,他们负责消费饺子皮。

多线程(JavaEE初阶系列4),JavaEE初阶,java-ee,java

在生产者和消费者之间,需要数据的交互,此时就需要一个交易场所

在上述的包饺子的场景下,此时如果A擀好了饺子皮,要给B、C、D就需要用一个东西先盛着,比如我们家里常用到的盖帘。此时这个盖帘就相当于是我们这里的交易场所

概念:生产者消费者模式就是通过一个容器来解决生产者和消费者的强耦合问题,生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不再等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取。

这里提到了一个概念叫“耦合”,不知道大家之前有没有听说过“高内聚,低耦合”,下面就给 大家分别解释一下“耦合”和“内聚”的概念吧!

耦合:是指两个模块之间的关联关系是强还是弱,关联越强耦合越高,关联越低耦合越低。

  • 举个例子:比如说是家里人如果生病了,那么此时我们就必须放下手头的工作去照顾家人,但是如果是你多年不联系的朋友生病了,那么我们最多就是多嘱咐他几句,让他好好休息,所以对于家人生病来说对我们的影响是比较大的,但是对于多年不联系的朋友来说对于我们的影响就比较小了,所以计算机中我们追求的是低耦合,避免代码牵一发而动全身。

内聚:相关联的代码,有没有放在一起,如果相关联的东西没有放在一起,随便乱放那就是低内聚,如果相关联的代码分门别类的规制起来就是高内聚。

  • 举个例子:如果你的衣服在家里是随便乱放,并且还不按照春夏秋冬保管起来,回家后衣服也就随随便便扔在一个角落,当你下次在找衣服的时候就会很麻烦,可能就需要找很久,这就是低内聚,而如果你的衣服是按照春夏秋冬分类放置,并且回家后衣服也是由固定的位置,鞋、衣服、袜子...都有专门的位置来摆放,那么你在寻找的时候就会非常方便,此时就是高内聚。所以我们在代码管理的时候也需要做到高内聚,将同一类的代码放置在一起,这样也方便后期的管理和应用。

2.2.1 上下游模块之间进行“解耦合”

那么了解了什么是“高内聚,低耦合”之后,在回到我们的生产者消费者模型这块,在上面给大家强调在生产者消费者模型中是要降低他两之间的耦合性,也就是“解耦合”,那么我们是如何做到解耦合的呢?就是小编在上述包饺子中举例子中的那个“盖帘”,通过这个“盖帘”我们就可以很好的降低它两之间的耦合性了,这里的盖帘在我们计算机中是有一个专门的数据结构来扮演的“阻塞式队列”。

比如我们先来考虑以下这个场景:

A服务器调用B服务器(A给B发送请求B给A返回响应)。

多线程(JavaEE初阶系列4),JavaEE初阶,java-ee,java

此时如果A和B直接通信,此时就是耦合比较高的情况。如果B挂了,对于A会有之间的影响,A也就跟着挂了。另外如果要再加个C,此时对于A就有一个比较大的调整。这就是高耦合的情况。那么我们自然是不希望在现实生活中出现这种情况。 所以就引入了生产者消费者模型,耦合就降低了,如下所示:

多线程(JavaEE初阶系列4),JavaEE初阶,java-ee,java

如上图所示,中间有一个阻塞队列服务器就会降低耦合性了,此时的A不知道B和C的存在,B和C也不知道A的存在,他们就只认识队列,此时的B挂了对于A来说是没有影响的。 

2.2.2削峰填谷

为了避免耦合性高的情况一种就是上述给大家讲解的通过中间的“阻塞队列服务器”来进行解耦合,另一种就是“削峰填谷”。考虑以下场景:

多线程(JavaEE初阶系列4),JavaEE初阶,java-ee,java

A收到的请求数量,是和用户的行为相关的,但是用户行为是随机的,有的情况下,请求会出现“峰值”突然爆发式增长,比如我们在学校强选修课的时候,所以如果是上述图示所示的情况下,当A收到一个峰值的同时,B也就会收到一个峰值,但是如果B设计的时候没有考虑到峰值处理的情况,可能就会挂掉,这就给系统的稳定性带来了风险。

解决方案:

多线程(JavaEE初阶系列4),JavaEE初阶,java-ee,java

 

此时A收到的请求多了,队列中的元素也就会越来越多,此时B任然可以按照之前处理数据的速度来处理队列中的数据,所以也就是队列帮助B承担了压力,此时B就不容易挂掉,也就达到了我们所说的“削峰填谷”的效果。这就相当于是我国建造的“三峡大坝”当遇到洪水的时候,大坝就起到了一个缓冲的效果,让下游的水不至于一下子太多,从而发生重大的人财损失,但是如果遇到干旱季节,大坝就会将之前储蓄的水在放出来,也不至于下游太干旱。 

 下面我们就用代码来实际给大家来演示一下吧。

代码展示:

package Thread;

import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;

public class ThreadDemo24 {
    public static void main(String[] args) {
        BlockingDeque<Integer> blockingDeque = new LinkedBlockingDeque<>();
        //消费者
        Thread t1 = new Thread(() -> {
            while (true) {
                int value = 0;
                try {
                    value = blockingDeque.take();
                    System.out.println("消费元素:" + value);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t1.start();

        //生产者
        Thread t2 = new Thread(() -> {
            int value = 0;
            while (true) {
                try {
                    System.out.println("生产元素:" + value);
                    blockingDeque.put(value);
                    value++;
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t2.start();

        //上述代码是让生产者每隔1s生产一个元素。
        //让消费者直接消费,不受限制
    }
}

结果展示:
多线程(JavaEE初阶系列4),JavaEE初阶,java-ee,java

2.3阻塞队列的实现

下面我们来自己实现一下阻塞队列:

实现阻塞队列我们分三步走:

  1. 先实现一个普通队列。
  2. 加上线程安全。
  3. 加上阻塞功能。

代码展示:

package Thread;
//基于数组实现队列
class MyBlockingQueue{
    private int[] items = new int[1000];
    //约定在[head,tail)为队列的有效元素
    volatile private int head = 0;
    volatile private int tail = 0;
    volatile private int size = 0;

    //入队列
    synchronized public void put(int elem) throws InterruptedException {
        while (size == items.length) {
            //队列已满
            // return;
            this.wait();
        }
        //把新元素放到tail所在的位置上
        items[tail] = elem;
        tail++;
        //万一tail达到了上限,就需要让tail从头开始
        if (tail == items.length){
            tail = 0;
        }
        //tail = tail % items.length
        size++;
        this.notify();
    }

    //出队列
    synchronized public Integer take() throws InterruptedException {
        while (size == 0){
//            return null;
            this.wait();
        }
        int value = items[head];
        head++;
        if (head == items.length) {
            head = 0;
        }
        size--;
        this.notify();
        return value;
    }
}
public class ThreadDemo25 {
    public static void main(String[] args) {
        MyBlockingQueue queue = new MyBlockingQueue();
        //消费者
        Thread t1 = new Thread(() -> {
            while (true) {
                try {
                    int value = queue.take();
                    System.out.println("消费:" + value);
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        //生产者
        Thread t2 = new Thread(() -> {
            int value = 0;
            while (true) {
                try {
                    System.out.println("生产:" + value);
                    queue.put(value);
                    value++;
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        t1.start();
        t2.start();

        System.out.println("hello");
    }
}


结果展示:
多线程(JavaEE初阶系列4),JavaEE初阶,java-ee,java

结束语:

这节中小编主要是与大家分享了设计模式中的两个重要的模式,单例模式和阻塞式队列,还给大家实现了一下阻塞式队列的代码,希望这节对大家学习JavaEE有一定的帮助,想要学习的同学记得关注小编和小编一起学习吧!如果文章中有任何错误也欢迎各位大佬及时为小编指点迷津(在此小编先谢过各位大佬啦!)文章来源地址https://www.toymoban.com/news/detail-608549.html

到了这里,关于多线程(JavaEE初阶系列4)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Java EE初阶八】多线程案例(计时器模型)

            计时器类似闹钟,有定时的功能,其主要是到时间就会执行某一操作,即可以指定时间,去执行某一逻辑(某一代码)。         在java标准库中,提供了Timer类,Timer类的核心方法是schedule( 里面包含两个参数,一个是要执行的任务代码,一个是设置多久之后

    2024年01月21日
    浏览(46)
  • JavaEE初阶:Java线程的状态

    目录 获取当前线程引用 休眠当前线程  线程的状态 1.NEW               2.TERMINATED  3.RUNNABLE 4.WAITING 5.TIMED_WAITING 6.BLOCKED 多线程的意义 单线程  多线程 这个方法返回当前线程的引用。但是我们会对static有疑惑,这其实是一个静态方法,更好的说法是这是一个 类方法, 调用这

    2024年02月11日
    浏览(42)
  • javaee初阶———多线程(三)

    T04BF 👋专栏: 算法|JAVA|MySQL|C语言 🫵 小比特 大梦想 此篇文章与大家分享多线程专题第三篇,关于 线程安全 方面的内容 如果有不足的或者错误的请您指出! 我们在前面说过,线程之间是抢占式执行的,这样产生的随机性,使得程序的执行顺序变得不一致,就会使得程序产生不同的结

    2024年04月16日
    浏览(38)
  • JavaEE初阶:多线程 - 编程

    我们在之前认识了什么是多进程,今天我们来了解线程。 一个线程就是一个 \\\"执行流\\\". 每个线程之间都可以按照顺讯执行自己的代码. 多个线程之间 \\\"同时\\\" 执行 着多份代码. 引入 进程 这个概念,主要是为了解决并发编程这样的问题。因为cpu进入了多核心的时代,要想进一步

    2024年02月12日
    浏览(37)
  • 【JavaEE初阶】 线程安全

    线程安全是多线程编程是的计算机程序代码中的一个概念。在拥有共享数据的多条线程并行执行的程序中,线程安全的代码会通过同步机制保证各个线程都可以正常且准确的执行,不会出现数据污染等意外情况。上述是百度百科给出的一个概念解释。换言之,线程安全就是某

    2024年02月08日
    浏览(53)
  • 【JavaEE初阶】 线程安全的集合类

    原来的集合类, 大部分都不是线程安全的. Vector, Stack, HashTable, 是线程安全的(不建议用), 其他的集合类不是线程安全的. 为什么不建议使用呢? 因为我们在使用的时候,这些类就会自动的加锁,虽然编译器会自动优化为没有锁竞争的线程进行锁消除的优化,但是呢万一编译器没

    2024年02月08日
    浏览(35)
  • 【JavaEE初阶】 线程池详解与实现

    线程池,是一种线程的使用模式,它为了降低线程使用中频繁的创建和销毁所带来的资源消耗与代价。 通过创建一定数量的线程,让他们时刻准备就绪等待新任务的到达,而任务执行结束之后再重新回来继续待命。 想象这么一个场景: 在学校附近新开了一家快递店,老板很

    2024年02月06日
    浏览(35)
  • 【JavaEE初阶】线程的概念与创建

    本节目标 认识多线程 创建多线程 Java 给多线程编程提供了内置的支持。 一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。 一个线程就是一个 “执行流” . 每个线程之间都可以按照顺讯执行自己的代码. 多个线程之

    2024年02月07日
    浏览(39)
  • JavaEE初阶Day 6:多线程(4)

    前序 :针对Day 5结尾的count++ 多线程的执行,是 随机调度抢占式 的执行模式,某个线程执行指令过程中,当它执行到任何一个指令的时候,都有可能被其他线程把它的CPU抢占走 实际并发执行,由于 上述原因 以及 count++本质是CPU的三个指令 ,两个线程执行指令的相对顺序就可

    2024年04月14日
    浏览(29)
  • 【JavaEE初阶】多线程(四)阻塞队列 定时器 线程池

    概念 阻塞队列是一种特殊的队列. 也遵守 “ 先进先出 ” 的原则. 阻塞队列能是一种线程安全的数据结构, 并且具有以下特性: 当队列满的时候, 继续入队列就会阻塞, 直到有其他线程从队列中取走元素. 当队列空的时候, 继续出队列也会阻塞,直到有其他线程往队列中插入元素

    2023年04月26日
    浏览(54)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包