ThreadLocal知识点总结

news2024/9/22 7:36:25

什么是ThreadLocal?它的作用是什么?

        ThreadLocal是线程Thread中属性threadLocals的管理者。

        ThreadLocal是Java中lang包下的一个类,可以用于在多线程环境中为每个线程维护独立的变量副本。它的作用是让每个线程都拥有自己的数据副本,避免了多个线程同时访问同一个变量的冲突问题。

ThreadLocal内部实现原理是什么?有哪些风险和注意事项?

        1.ThreadLocal

        ThreadLocal 是一个泛型类,它的主要作用是提供一个用于存储线程局部变量的容器。每个线程都有一个 ThreadLocalMap 对象,可以用来存储该线程的所有 ThreadLocal 实例及其对应的值。

        ThreadLocal 的内部实现非常简单,它只有两个方法:

  • get():用来获取当前线程的局部变量。
  • set(T value):用来设置当前线程的局部变量的值。

        2.ThreadLocalMap

        ThreadLocalMap 是一个内部类,用于存储每个线程的局部变量。它是一个类似于哈希表的数据结构,内部使用 Entry 对象来存储键值对。每个 Entry 对象包含三个部分:ThreadLocal 实例、该实例对应的值以及下一个 Entry 对象的引用。

ThreadLocalMap 的实现原理比较简单,主要包含以下几个步骤:

  • 获取当前线程的 ThreadLocalMap 对象。
  • 使用 ThreadLocal 实例作为 key 查找对应的 Entry 对象。
  • 如果查找到了 Entry 对象,则将该 Entry 对象的 value 设置为指定的值。
  • 如果没有查找到 Entry 对象,则创建一个新的 Entry 对象,并将该 Entry 对象插入到 ThreadLocalMap 中。

在使用 ThreadLocal 的过程中,需要注意一些风险和注意事项:

        1.内存泄漏

        由于 ThreadLocalMap 中的 Entry 对象使用了强引用来引用 ThreadLocal 实例,在线程结束时如果没有清除相应的引用,就会导致内存泄漏的问题。因此,在使用 ThreadLocal 时需要及时清除相应的引用,以避免出现内存泄漏的问题。

        2.线程安全

        由于 ThreadLocalMap 存储的是线程局部变量,因此在多线程并发的场景下,需要注意线程安全的问题。通常情况下,使用 ThreadLocal 可以帮助我们避免多线程间的数据冲突,但是如果 ThreadLocal 存储的是共享变量,则仍然需要采取相应的措施来保证线程安全。

        3.不要滥用

        ThreadLocal 虽然可以帮助我们实现线程间的数据隔离,但是不适合在任何场景下使用。滥用 ThreadLocal 会导致代码的可读性和可维护性降低,并且会增加内存的使用,从而影响系统性能。

        4.适当使用

        在使用 ThreadLocal 时,需要根据具体的业务场景来选择合适的方案,避免出现不必要的问题。通常情况下,使用 ThreadLocal 可以帮助我们实现线程间数据隔离,但是需要注意一些细节,比如:

  • 在使用 ThreadLocal 时,应该尽量避免使用静态变量或单例模式,以避免出现数据混乱的问题。
  • 在使用 ThreadLocal 时,需要及时清除相应的引用,避免出现内存泄漏的问题。
  • 在使用 ThreadLocal 时,需要尽量避免使用过多的线程,以避免影响系统的性能。
  • 在使用 ThreadLocal 时,需要注意一些细节,比如在 Spring 中使用 ThreadLocal 时,应该将 ThreadLocal 设置为静态的,以避免出现数据混乱的问题。

        总之,ThreadLocal 在 Java 开发中的应用非常广泛,但是使用不当会带来一些风险和注意事项。因此,在使用 ThreadLocal 时,需要充分了解其内部实现原理和注意事项,以避免出现不必要的问题。

ThreadLocal的使用场景有哪些?举例说明。

        ThreadLocal 主要用于实现线程间的数据隔离,其使用场景比较多,下面列举几个比较常见的场景:

        1.数据库连接管理

在基于 JDBC 进行数据库操作时,每个线程都需要获取一个独立的数据库连接,这个连接需要通过数据库连接池来获取。在这种情况下,可以使用 ThreadLocal 来实现连接的管理,每个线程都拥有自己的连接,避免了线程间的数据混乱。

public class DBUtils {
    private static final ThreadLocal<Connection> connectionHolder = new ThreadLocal<Connection>() {
        @Override
        protected Connection initialValue() {
            // 创建数据库连接
            return createConnection();
        }
    };

    public static Connection getConnection() {
        return connectionHolder.get();
    }

    public static void releaseConnection() {
        Connection connection = connectionHolder.get();
        connectionHolder.remove();
        connection.close();
    }

    private static Connection createConnection() {
        // 创建数据库连接
    }
}

        2. Session管理

        在 Web 应用中,每个用户都有自己的会话(Session),这个会话信息需要存储在服务器端。使用 ThreadLocal 可以实现会话信息的存储和管理,每个线程拥有自己的 Session 对象,避免了线程间的数据混乱。

public class SessionUtils {
    private static final ThreadLocal<Session> sessionHolder = new ThreadLocal<Session>() {
        @Override
        protected Session initialValue() {
            // 创建 Session 对象
            return createSession();
        }
    };

    public static Session getSession() {
        return sessionHolder.get();
    }

    public static void releaseSession() {
        Session session = sessionHolder.get();
        sessionHolder.remove();
        session.close();
    }

    private static Session createSession() {
        // 创建 Session 对象
    }
}

        3. 用户身份信息传递

        在一些框架中,比如 Spring、Shiro 等,用户的身份信息需要在整个请求处理过程中传递,这个身份信息需要存储在 ThreadLocal 中。这种方式可以方便地在整个请求处理过程中获取用户的身份信息,避免了在各个方法中传递参数的麻烦。

public class UserContext {
    private static final ThreadLocal<User> userHolder = new ThreadLocal<>();

    public static void setCurrentUser(User user) {
        userHolder.set(user);
    }

    public static User getCurrentUser() {
        return userHolder.get();
    }

    public static void clearCurrentUser() {
        userHolder.remove();
    }
}

        总之,ThreadLocal 可以用于实现线程间的数据隔离,在 Java 开发中应用非常广泛,使用方便,但是在使用时需要注意一些细节,避免出现数据混乱和内存泄漏等问题。

如何防止ThreadLocal造成内存泄漏?

        虽然 ThreadLocal 可以很方便地实现线程间数据隔离,但是它也容易引发内存泄漏的问题。ThreadLocal 内存泄漏的根本原因是因为 ThreadLocalMap 中的 Entry 引用了 ThreadLocal 实例,在线程结束时没有被垃圾回收。

        当一个线程结束时,它所持有的 ThreadLocalMap 实例会随之被垃圾回收,但是 ThreadLocalMap 中的 Entry 对象却不会被回收。因为每个 Entry 对象都持有一个对应的 ThreadLocal 实例的强引用,如果没有手动清除该引用,那么 ThreadLocal 实例将无法被垃圾回收,从而导致内存泄漏。

        这种内存泄漏的情况在使用线程池的场景下尤其容易出现。线程池中的线程在结束后不会被销毁,而是会被重新利用,如果这个线程在之前被使用过 ThreadLocal,并且没有清除相关的 ThreadLocal 引用,那么下一次使用该线程时,就会出现内存泄漏的问题。

        因此,在使用 ThreadLocal 时,需要注意以下几点:

  1. 及时清除 ThreadLocal 引用,可以手动调用 ThreadLocal 的 remove 方法来清除 ThreadLocal 实例。
  2. 不要在 ThreadLocal 中存储大量数据,以免占用过多内存。
  3. 尽量使用局部变量来代替 ThreadLocal。

        值得注意的是,在 JDK 1.5 版本中,ThreadLocal 的实现发生了改变。之前的实现中,ThreadLocalMap 中的 Entry 对象是使用强引用来引用 ThreadLocal 实例的,从而导致内存泄漏。而在 JDK 1.5 中,ThreadLocalMap 中的 Entry 对象使用的是 WeakReference 弱引用来引用 ThreadLocal 实例,这样 ThreadLocal 实例就可以被垃圾回收了,从而避免了内存泄漏的问题。但是,需要注意的是,使用 WeakReference 弱引用也有一些注意事项,比如需要及时调用 remove 方法来清除 Entry 对象等。

ThreadLocal为什么会引发空指针异常?如何避免?

        ThreadLocal 引发空指针异常的原因是没有正确的初始化 ThreadLocal 的初始值,或者在获取 ThreadLocal 对象时没有正确的处理 null 的情况。当 ThreadLocal 对象的初始值为 null 时,在没有调用 set 方法的情况下,get 方法会返回 null,而这个 null 值有可能会引发空指针异常。

        下面是一个简单的例子,用来说明 ThreadLocal 引发空指针异常的原因:

public class ThreadLocalExample {
    private static final ThreadLocal<String> threadLocal = new ThreadLocal<>();

    public static void main(String[] args) {
        threadLocal.set("Hello, World!");
        String value = threadLocal.get();
        System.out.println(value.length());
        threadLocal.remove();
        String value2 = threadLocal.get();
        System.out.println(value2.length());
    }
}

        上面的代码中,我们先调用了 set 方法将一个字符串保存在 ThreadLocal 对象中,然后通过 get 方法获取这个字符串并调用了 length 方法。接着我们又调用了 remove 方法来清除 ThreadLocal 对象中保存的字符串,最后再次调用 get 方法获取字符串并调用 length 方法。在第二次调用 get 方法时,由于没有调用 set 方法,所以 get 方法会返回 null,然后我们又调用了 length 方法,这时就会抛出空指针异常。

        为了避免 ThreadLocal 引发空指针异常,可以在获取 ThreadLocal 对象时先判断是否为 null。如果为 null,可以使用默认值或者手动初始化一个值,避免出现空指针异常。

public class ThreadLocalExample {
    private static final ThreadLocal<String> threadLocal = new ThreadLocal<>();

    public static void main(String[] args) {
        threadLocal.set("Hello, World!");
        String value = threadLocal.get();
        if (value != null) {
            System.out.println(value.length());
        }
        threadLocal.remove();
        String value2 = threadLocal.get();
        if (value2 != null) {
            System.out.println(value2.length());
        }
    }
}

        在上面的例子中,我们在调用 get 方法之前都对其进行了 null 判断,避免了出现空指针异常。此外,在使用 ThreadLocal 时,也应该尽量避免出现 null 值,可以通过设置默认值或者手动初始化的方式来避免空指针异常的出现。

ThreadLocal与线程池的关系是什么?如何避免在使用线程池时出现ThreadLocal带来的问题?

        ThreadLocal 与线程池的关系是,当使用线程池时,如果在线程池中使用 ThreadLocal 对象,需要注意 ThreadLocal 对象在每个线程中的唯一性。如果多个线程共享了同一个 ThreadLocal 对象,会导致线程安全问题。

        在使用线程池时,可以采用以下方式来避免 ThreadLocal 带来的问题:

  1. 在使用线程池时,应该避免在线程池中共享 ThreadLocal 对象。每个线程应该拥有自己的 ThreadLocal 对象,这样可以避免多个线程共享同一个 ThreadLocal 对象带来的线程安全问题。
  2. 在使用线程池时,应该在每次使用线程之前调用 ThreadLocal 的 set 方法,为每个线程初始化 ThreadLocal 对象的初始值。这样可以避免在多个线程共享同一个 ThreadLocal 对象时出现未初始化的情况。
  3. 在使用线程池时,应该在每次使用完线程之后,调用 ThreadLocal 的 remove 方法,手动清除 ThreadLocal 对象的值。这样可以避免在下次使用同一个线程时,出现上一次留下的 ThreadLocal 对象的值的情况。
  4. 如果在使用线程池时,必须共享一个 ThreadLocal 对象,可以使用 InheritableThreadLocal 类,这个类可以让子线程继承父线程中的 ThreadLocal 变量。但是使用 InheritableThreadLocal 会增加线程之间的耦合,可能会影响代码的可维护性。

        下面是一个简单的例子,用来说明如何避免在使用线程池时出现 ThreadLocal 带来的问题:

public class ThreadLocalExample {
    private static final ThreadLocal<Integer> threadLocal = new ThreadLocal<>();

    public static void main(String[] args) throws InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(2);

        for (int i = 0; i < 10; i++) {
            int finalI = i;
            executorService.execute(() -> {
                threadLocal.set(finalI);
                System.out.println(Thread.currentThread().getName() + ": " + threadLocal.get());
                threadLocal.remove();
            });
        }

        executorService.shutdown();
    }
}

        在上面的例子中,我们创建了一个大小为 2 的线程池,然后提交了 10 个任务,每个任务都向 ThreadLocal 对象中保存一个整数,然后输出当前线程的名称和 ThreadLocal 对象中保存的整数。在每次使用完 ThreadLocal 对象后,我们都手动调用了 remove 方法清除 ThreadLocal 对象的值,避免了在下次使用同一个线程时出现上一次留下的 ThreadLocal 对象的值的情况。

如果使用ThreadLocal存储一些数据,那么这些数据对于其他线程是否可见?如何实现跨线程共享ThreadLocal中的数据?

        ThreadLocal 存储的数据只对当前线程可见,其他线程无法直接访问 ThreadLocal 中的数据。这是因为 ThreadLocal 存储的数据是与线程绑定的,每个线程都有自己独立的 ThreadLocal 实例和数据存储空间。不同的线程之间访问不同的 ThreadLocal 实例,所以存储在 ThreadLocal 中的数据也是线程独享的。

        如果想要实现跨线程共享 ThreadLocal 中的数据,可以使用一个公共的数据结构来存储数据,然后将这个数据结构存储在 ThreadLocal 中,以达到线程独享的效果。这样不同线程可以通过访问同一个 ThreadLocal 对象,来访问公共的数据结构。

        例如,我们可以使用一个 HashMap 来存储需要共享的数据,然后将这个 HashMap 存储在 ThreadLocal 中:

public class SharedData {
    private static final ThreadLocal<Map<String, Object>> threadLocal = new ThreadLocal<Map<String, Object>>() {
        @Override
        protected Map<String, Object> initialValue() {
            return new HashMap<>();
        }
    };

    public static void set(String key, Object value) {
        threadLocal.get().put(key, value);
    }

    public static Object get(String key) {
        return threadLocal.get().get(key);
    }
}

        在上面的代码中,我们定义了一个名为 SharedData 的类,其中有两个方法 set 和 get,分别用来设置和获取需要共享的数据。这些数据存储在一个名为 threadLocal 的 ThreadLocal 对象中,ThreadLocal 的类型为 Map<String, Object>。在 initialValue 方法中,我们创建了一个 HashMap 作为初始值,以便在每个线程中都有一个独立的 Map 实例。

        我们可以在不同的线程中使用 set 方法和 get 方法来存储和访问需要共享的数据。由于每个线程都有自己独立的 Map 实例,不同的线程之间对于 threadLocal 存储的 Map 实例的修改是互不干扰的,实现了数据的跨线程共享。

ThreadLocal与InheritableThreadLocal有何区别?在什么情况下会选择使用InheritableThreadLocal?

        ThreadLocal 和 InheritableThreadLocal 都是 Java 中用于实现线程本地存储的类,它们的主要区别在于数据的继承方式。

        在使用 ThreadLocal 存储数据时,每个线程都有自己独立的 ThreadLocal 实例和数据存储空间。不同的线程之间访问不同的 ThreadLocal 实例,所以存储在 ThreadLocal 中的数据也是线程独享的。这种方式的好处是,每个线程都拥有自己独立的数据存储空间,不同线程之间的数据互不干扰,可以避免并发访问的问题。

        而 InheritableThreadLocal 继承了 ThreadLocal,它的作用是让子线程可以访问父线程的 ThreadLocal 变量。也就是说,在使用 InheritableThreadLocal 存储数据时,子线程会继承父线程的 ThreadLocal 变量,并且可以对其进行修改,从而实现了跨线程的数据传递。

        在一些场景中,需要将一些数据从主线程传递到子线程中,这时候就可以使用 InheritableThreadLocal 来实现。例如,在 Web 应用中,一个请求可能会创建多个线程去处理不同的任务,这时候可以使用 InheritableThreadLocal 将一些用户信息等数据从主线程传递到子线程中,避免重复查询数据库或重复计算等问题。

        需要注意的是,在使用 InheritableThreadLocal 时,由于子线程会继承父线程的 ThreadLocal 变量,因此可能会导致数据共享的问题,需要特别注意线程安全。此外,由于每个线程都会继承父线程的 ThreadLocal 变量,因此在使用 InheritableThreadLocal 时需要注意内存泄漏问题,及时清理不再使用的 ThreadLocal 变量。

ThreadLocal的实现机制是否线程安全?如果不安全,该如何解决?

        ThreadLocal 的实现机制本身是线程安全的。在实现中,每个线程都会有自己独立的 ThreadLocal 实例和数据存储空间,不同线程之间互不干扰,因此不存在线程安全的问题。

        但是,在使用 ThreadLocal 存储数据时,如果数据本身是可变的,那么就需要考虑线程安全的问题了。因为不同线程之间访问同一个可变数据时,可能会出现并发访问的问题,导致数据不一致或出现异常。

        为了解决这个问题,一般的做法是使用线程安全的数据结构来存储数据,例如使用 ConcurrentHashMap 代替普通的 HashMap,或者使用线程安全的 List、Set 等数据结构。同时,也可以使用 synchronized 或者 Lock 等机制来实现对可变数据的同步访问,保证线程安全。

        此外,还可以考虑使用不可变对象来存储数据。如果存储的数据是不可变的,那么就不需要考虑线程安全的问题了,因为不可变对象一旦创建,其状态就不会再发生改变。

        总之,ThreadLocal 的实现机制本身是线程安全的,但是在存储可变数据时需要考虑线程安全的问题,可以使用线程安全的数据结构同步机制来实现。同时,如果存储的数据是不可变的,就可以避免线程安全的问题。

在Java中,如何使用ThreadLocal实现一个线程安全的单例模式?

        在 Java 中,可以使用 ThreadLocal 来实现线程安全的单例模式。线程安全的单例模式指的是在多线程环境下,能够保证每个线程只能获取到唯一的单例对象,且不同线程之间互不干扰,避免出现线程安全问题。

        下面是一个使用 ThreadLocal 实现线程安全的单例模式的示例代码:

public class ThreadSafeSingleton {
    private static final ThreadLocal<ThreadSafeSingleton> threadLocalInstance = new ThreadLocal<ThreadSafeSingleton>() {
        @Override
        protected ThreadSafeSingleton initialValue() {
            return new ThreadSafeSingleton();
        }
    };

    private ThreadSafeSingleton() {}

    public static ThreadSafeSingleton getInstance() {
        return threadLocalInstance.get();
    }
}


        在上面的代码中,ThreadLocal 实例 threadLocalInstance 的泛型参数指定为 ThreadSafeSingleton 类型。在 ThreadLocal 中,为每个线程创建一个独立的 ThreadSafeSingleton 对象。在调用 getInstance 方法时,会先通过 threadLocalInstance.get() 方法获取当前线程对应的单例对象,如果不存在则会调用 initialValue 方法来创建一个新的单例对象。

        由于每个线程都有独立的对象实例,因此不会出现多个线程同时访问同一个单例对象的情况,从而保证线程安全。

        需要注意的是,由于每个线程都有独立的对象实例,因此在使用 ThreadLocal 实现线程安全的单例模式时,需要考虑内存泄漏问题。可以使用一些技巧来避免这种情况,例如使用 WeakReference 引用对象,或者在不需要的时候手动将对象从 ThreadLocal 中移除等。

其他问题补充

Netty的FastThreadLocal到底有多快?
 

ThreadLocal是什么?有哪些用途?你了解多少?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/357540.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java面向对象的特性:封装,继承与多态

Java面向对象的特性 在学习Java的过程是必须要知道的Java三大特性&#xff1a;封装、继承、多态。如果要分为四类的话&#xff0c;加上抽象特性。 封装 1.封装概述 是面向对像三大特征之一&#xff08;封装&#xff0c;继承&#xff0c;多态&#xff09; 是面向对象编程语言对客…

语音增强学习路线图Roadmap

语音增强算是比较难的研究领域&#xff0c;从入门到精通有很多台阶&#xff0c;本文介绍一些有价值的书籍&#xff0c;值得反复阅读。主要分为基础类和进阶类书籍&#xff0c;大多都是理论和实践相结合的书籍&#xff0c;编程实践是抓手,让知识和基础理论变扎实。基础书籍《信号…

RT-Thread初识学习-01

1. RT-Thread 简介 1.1 RT-Thread 是什么 据不完全统计&#xff0c;世界有成千上万个 RTOS&#xff08;Real-time operating system&#xff0c;实时操作系统&#xff09;&#xff0c;RT-Thread 就是其中一个优秀的作品。 RT-Thread 内核的第一个版本是熊谱翔先生在 2006 年…

分布式-分布式存储笔记

读写分离 什么时候需要读写分离 互联网大部分业务场景都是读多写少的&#xff0c;读和写的请求对比可能差了不止一个数量级。为了不让数据库的读成为业务瓶颈&#xff0c;同时也为了保证写库的成功率&#xff0c;一般会采用读写分离的技术来保证。 读写分离的实现是把访问的压…

LeetCode-384-打乱数组

1、列表随机 为了能够初始化数组&#xff0c;我们使用nums保存当前的数组&#xff0c;利用orignal保存初始化数组。为了实现等可能随机打乱&#xff0c;考虑到随机数本质上是基于随机数种子的伪随机&#xff0c;我们采用如下的方式实现等可能随机&#xff1a;我们将所有元素压…

MySQL备份恢复(十二)

文章目录1. MySQL数据损坏类型1.1 物理损坏1.2 逻辑损坏2. DBA运维人员备份/恢复职责2.1 设计备份/容灾策略2.1.1 备份策略2.1.2 容灾策略2.2 定期的备份/容灾检查2.3 定期的故障恢复演练2.4 数据损坏时的快速准确恢复2.5 数据迁移工作3. MySQL常用备份工具3.1 逻辑备份方式3.2…

【scl】博图程序的导入和导出

导入或者导出博图文件的方法&#xff08;也叫移植文件&#xff09; 目录 前言 ​编辑 ​编辑 前言 本篇文章主要写一下关于博图文件的导入和导出&#xff0c;具体要怎么样才能将写好的程序或者块移植到其他地方&#xff0c;下面我们一起来看&#xff01; 一、程序块的导入和导…

[软件工程导论(第六版)]第4章 形式化说明技术(课后习题详解)

文章目录1. 举例对比形式化方法和欠形式化方法的优缺点。2. 在什么情况下应该使用形式化说明技术&#xff1f;使用形式化说明技术时应遵守哪些准则&#xff1f;3. 一个浮点二进制数的构成是&#xff1a;一个可选的符号&#xff08;&#xff0b;或&#xff0d;&#xff09;&…

Seata分布式事务框架-AT模式与TCC模式介绍

Seata分布式事务框架-AT模式介绍 Seata AT事务方案 Seata 的 AT 模式&#xff08;Automatic Transaction&#xff09;是一种无侵入的分布式事务解决方案。下面结合具体业务场景来分析其执行的原理。 业务场景 订单系统 当用户下订单时&#xff0c;执行以下三步流程&#x…

【NLP开发】Python实现聊天机器人(Selenium、七嘴八舌)

&#x1f37a;NLP开发系列相关文章编写如下&#x1f37a;&#xff1a;1&#x1f388;【NLP开发】Python实现词云图&#x1f388;2&#x1f388;【NLP开发】Python实现图片文字识别&#x1f388;3&#x1f388;【NLP开发】Python实现中文、英文分词&#x1f388;4&#x1f388;【…

XSS注入进阶练习篇(二)DOM型XSS注入深入

DOM型XSS注入深入1. SVG 劫持JS执行1.1 DOM树的概念与构建过程1.1.1 什么是DOM树&#xff1f;1.1.2 DOM树的构建过程1.2 探究img失败的原因1.3 svg标签劫持innerhtml2. details标签 特定条件下劫持JS执行2.1 事件触发流程2.2 实例3.DOM clobbering 绕过3.1 什么是DOM clobberin…

Redis内存回收

Redis 内存回收 Redis之所以性能很强&#xff0c;最主要的原因是基于内存存储&#xff0c;然而单节点的Redis其内存大小不宜过大&#xff0c;会影响持久化或主从同步性能 可以通过修改配置文件来设置Redis的最大内存 maxmemory <bytes>当内存达到上限时&#xff0c;就…

营销狂人杜国楹的两大顶级思维

“营销狂人”小罐茶 杜国楹两大顶级思维 1.一定要有【参照物思维】 2.一定要有【终局思维】 趣讲大白话&#xff1a;大牛的思考就是不同 *********** 杜国楹对茶行业思考 1.参照咖啡、酒的发展路径 2.中国茶工业化,品牌化是唯一壮大之路 3.龙头企业必须全品 没有参照物思维就没…

Python将内容写入文件的方法总结。

使用Python写入文件是我们coder的日常&#xff0c;本篇带你详细看一下python将内容写入文件的方法以及细节。主要包括write()方法、writelines() 方法、print() 函数、使用 csv 模块、使用 json 模块。 目录 一、write()方法 二、writelines() 方法 三、print() 函数 四、使…

【Java】中的各种锁

Java提供了种类丰富的锁&#xff0c;每种锁因其特性的不同&#xff0c;在适当的场景下能够展现出非常高的效率。 一、Java锁是什么&#xff1f;为什么要用Java锁&#xff1f; 在并发编程中&#xff0c;经常遇到多个线程访问同一个共享资源 &#xff0c;这时候作为开发者必须考…

【汇编】一、环境搭建(一只 Assember 的成长史)

嗨~你好呀&#xff01; 我是一名初二学生&#xff0c;热爱计算机&#xff0c;码龄两年。最近开始学习汇编&#xff0c;希望通过 Blog 的形式记录下自己的学习过程&#xff0c;也和更多人分享。 这篇文章主要讲述汇编环境的搭建过程。 话不多说~我们开始吧&#xff01; 系统环…

Ubuntu下安装 ntfs-3g

目录1.FAT32、NTFS和exFAT2.ubuntu 安装 ntfs-3g2.1 直接安装2.2 源码安装1.FAT32、NTFS和exFAT U盘在格式化的时候都会有三种格式分别是FAT32、NTFS和exFAT。 FAT32格式   FAT32格式硬盘分区的最大容量为2TB&#xff0c;虽然U盘做不到&#xff0c;但是现在1xTB硬盘都有了&…

实现8086虚拟机(三)——指令解码

文章目录中间指令格式解码模块的实现编译器将汇编语句翻译成机器指令&#xff0c;而虚拟机做的工作正好相反&#xff0c;就是将机器指令解码成可以识别的中间形式&#xff0c;然后执行。为什么要这么做&#xff1f;拿 mov 指令举例&#xff0c;看下它的机器指令的格式&#xff…

手动创建 vue2 ssr 开发环境

本文和个人博客同步发表 更多优质文章查看个人博客 前言 手动搭建 vue ssr 一直是一些前端开发者的噩梦&#xff0c;因为其中牵扯到很多依赖包之间的配置以及webpack在node中的使用。就拿webpack配置来说&#xff0c;很多前端开发者还是喜欢用webpack-cli脚手架搭建项目。导致…

NCHW - NHWC - CHWN 排列

TensorFlow有两种数据格式NHWC和NCHW,默认的数据格式是NHWC,可以通过参数data_format指定数据格式。这个参数规定了 input Tensor 和 output Tensor 的排列方式。 1、data_format 设置为 “NHWC” 时,排列顺序为 [batch, height, width, channels] 设置为 “NCHW” 时,排…