首页 > 编程语言 >Java基础总结

Java基础总结

时间:2024-08-03 15:27:42浏览次数:10  
标签:总结 Java 基础 System ThreadLocal 线程 内存 println out

1,Java JMM(java内存模型)

这个内存模型搞起来还是有点弯弯绕,一点点的整理吧。JMM的目的就是保证共享变量在多线程环境下的原子性,可见性,与有序性而定义的一组规范。这些问题的出现都跟CPU的设计有关系,CPU是计算机的运算核心所有的操作或者说指令都是在CPU里面运行的,而且CPU的运行效率超级高,比内存的运行速率还要高出几个数量级,做开发的肯定都知道内存比硬盘快几个数量级,会使用内存缓存来提高运行速率,但是使用了内存缓存就会出现数据不一致的问题,我们会采取各种措施来保证数据的一致性,这里不展开讨论缓存的问题。还是说回CPU,既然CPU的运行速率比内存快的多,设计者也设计了CPU的高速缓存来充分利用CPU的性能提高程序的运行效率。多了这个高速缓存,同样也会出现数据不一致的问题,于是就有了缓存一致性协议如MESI协议等,就是保证数据的一致性。各种操作系统运行在CPU等硬件之上同样要解决这个问题,于是不同的操作系统也有自己的内存模型。而java程序运行在JVM之上,而且支持平台一致,支持多线程并发,为了保证各个平台运行结果一致,保证共享数据在多线程环境下的一致有序,制定了JMM规范,所有的JVM都要遵从该规范,保证java程序的平稳高速运行。我们平时开发用到的(我现在接触到的)就是一个volatile和syncronized两个关键字,还有锁机制。当然还有其他原则,这里不涉及。而volatile的作用就是保证共享数据的可见性,使用的技术叫做内存屏障。内存屏障这个词听起来不是很好理解是英语直译,用中国话说就是内存数据的写入和读取的顺序以及方式,你不是有主内存还有cpu缓存还有什么堆内存栈内存吗?好一个内存屏障的指令可以规定数据从哪里读取,又该啥时同步。好了到这里了,一个 volatile 关键字的demo,贴在下面:

/**
 * volatile 可以保证共享变量的可见性,所谓可见性就是 保证变量的操作都是在共享堆内存中进行,而不是线程变量。
 */
public class VolatileTest {

    private static boolean flag = false;
    private static volatile boolean volatileFlag = false;

    public static void main(String[] args) throws InterruptedException {
        new Thread(() -> {
            while (!flag) { //程序会在这里死循环,因为之后的代码虽然对该属性做了修改,但对于该线程不可见。
            }
            System.out.println("Flag is now true!");
        }).start();

        new Thread(() -> {
            while (!volatileFlag) { //使用volatile修饰的变量只要发生变化对所有线程可见。
            }
            System.out.println("volatileFlag is now true!");
        }).start();

        Thread.sleep(1000);

        flag = true;
        System.out.println("Flag is set to true!");

        volatileFlag = true;
        System.out.println("volatileFlag is set to true!");
    }
}
2,ThreadLocal 与 SimpleDateFormat

首先是平时经常使用的 SimpleDateFormat 是线程不安全的,我平时都是现用现new的,据说这样子有点浪费系统资源。查阅相关资料后发现还可以结合ThreadLocal来使用,就是将df对象绑定在线程上,在空间和效率之间取得一点平衡。ThreadLocal,这个东西设计的很奇怪。你本身是用来操作Thread类里面的threadLocalMap的,你叫个ThreadLocalMapUtils不比ThreadLocal好理解啊?总之这个类就是将一个对象绑定在线程上,不同的线程会创建不同的对象(也有可能是克隆如果实现了clone方法的话)比如下面的例子。也就是说所有线程不安全的类(变量)都可以绑定在ThreadLocal上面呗?


import java.text.DateFormat;
import java.text.SimpleDateFormat;

/**
 * ThreadLocal 为每一个线程提供了独立的变量副本。也就是说 get() set() 方法是基于线程的,线程不一样获取到的对象就不一样。
 * 使用场景:
 * 适合保存和传递每个线程独立的数据,比如基于线程执行的用户信息,会话信息等,注意如果内部启用了新线程(子线程)会导致数据不一致。
 * 而且基于线程池的线程对象不会被回收,ThreadLocal变量也就不会被回收,所以使用完毕手动清除是个好习惯 threadLocal.remove();
 *
 */
public class ThreadLocalTest {

    static ThreadLocal<MyObject> threadLocal = ThreadLocal.withInitial(() -> {
        MyObject myObject = new MyObject();
        System.out.println(myObject);//com.kuafu.MyObject@22f71333 //com.kuafu.MyObject@29702e06 这里会执行两次,因为有两个线程来访问
        return myObject;
    });

    private static ThreadLocal<DateFormat> tlDf = ThreadLocal.withInitial(() -> {
        final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println(simpleDateFormat);//java.text.SimpleDateFormat@4f76f1a0 //java.text.SimpleDateFormat@4f76f1a0
        return simpleDateFormat;
    });


    public static void main(String[] args) {
        final MyObject myObject = threadLocal.get();
        System.out.println(myObject);//com.kuafu.MyObject@22f71333

        new Thread("t1"){
            @Override
            public void run() {
                final MyObject myObject1 = threadLocal.get();
                System.out.println(myObject1); //com.kuafu.MyObject@29702e06
                System.out.println(myObject == myObject1); //false
                System.out.println(myObject.equals(myObject1)); //false
            }
        }.start();

        final DateFormat dateFormat = tlDf.get();
        System.out.println(dateFormat); //java.text.SimpleDateFormat@4f76f1a0

        new Thread("t1"){
            @Override
            public void run() {
                final DateFormat dateFormat1 = tlDf.get();
                System.out.println(dateFormat1); //java.text.SimpleDateFormat@4f76f1a0
                System.out.println(dateFormat == dateFormat1); //false 这里看起来是个浅克隆?
                System.out.println(dateFormat.equals(dateFormat1)); //true
            }
        }.start();
    }

}

标签:总结,Java,基础,System,ThreadLocal,线程,内存,println,out
From: https://blog.csdn.net/lx18854869896/article/details/140889463

相关文章

  • 学生java学习路程-5
    ok,到了一周一次的总结时刻,我大致会有下面几个方面的论述:1.这周学习了Java的那些东西2.这周遇到了什么苦难3.未来是否需要改进方法等几个方面阐述我的学习路程。抽象类abstract接口interface,定义时加入注释解释接口含义String类String是不可变字符串,所有的替换,截取子字符串,......
  • Java SE核心技术——9抽象类
    面向对象编程(Object-OrientedProgramming,简称OOP)和面向过程编程(Procedure-OrientedProgramming)是两种不同的编程范式,它们在设计和实现软件时采用了不同的方法和哲学。一、面向对象编程核心概念:面向对象编程的核心是"对象",对象可以包含数据(属性)和代码(方法)。万物皆对象。封......
  • 基础实验3-2.4 出栈序列的合法性
    给定一个最大容量为m的堆栈,将n个数字按1,2,3,...,n的顺序入栈,允许按任何顺序出栈,则哪些数字序列是不可能得到的?例如给定m=5、n=7,则我们有可能得到{1,2,3,4,5,6,7},但不可能得到{3,2,1,7,5,6,4}。输入格式:输入第一行给出3个不超过1000的正整数:m......
  • Caused by: java.lang.ClassNotFoundException:org.apache.hadoop.hive.conf.hiveConf
    在sqoop执行create-hive-table时候报错这样,java.io.IOException:原因是缺失jar包,可能是sqoop conf文件的sqoop-env-template.sh里面没有配置相关的hadoop hivezookeeper 的相关环境变量进入sqoop的conf文件下找到sqoop-env-template.sh进入添加相关得到环境变量(注意......
  • Flink 开发语言选择 —— Java vs Scala
    引言ApacheFlink是一个用于处理无界和有界数据流的开源分布式计算框架。随着Flink的日益流行,越来越多的开发者开始考虑使用哪种编程语言来进行Flink应用程序的开发。本文将探讨在Flink中使用Java和Scala的优缺点,并帮助你做出更明智的选择。1.背景简介Flink支......
  • 搞定Java ArrayList,就看这一篇!
    大家好,我是小欧!今天我们来聊聊Java中的ArrayList。作为一个Java新手,初次接触ArrayList可能会觉得有点懵,不过不用担心,这篇文章会带你从零开始一步步搞定ArrayList。我们会从基础概念开始,然后逐步深入,最后通过几个实际案例来巩固学习成果。ArrayList是什么?简单来说,ArrayLis......
  • 单个或两个及以上java安装与环境变量配置
    目录java下载地址:1.安装java1.1安装程序1.2选择安装路径1.3等待安装2.首先,进入环境变量2.1找到设置(第一个win11,第二个win10)2.2进入到系统高级系统设置(第一个win11,第二个win10)2.3点击环境变量2.4新建与添加2.5添加CLASSPATH2.6添加JAVA_HOME2.7找到path,编辑......
  • 【Python】python基础
    本篇文章将讲解以下知识点:(1)循环语句(2)字符串格式化(3)运算符一:循环语句循环语句有两种:while   for本篇文章只讲解while循环格式:while 条件:  代码(只有条件为真的时候,此代码才会被执行,此处的代码可以是多行代码)(1)循环语句基本使用示例1:此处代码执行过程:1<3......
  • Java数据类型
    目录数据类型基本数据类型引用类型数据类型的转换数据类型基本数据类型Java语言提供了八种基本类型。六种数字类型(四个整数型,两个浮点型),一种字符类型,还有一种布尔型1.byte:byte数据类型是8位、有符号的,以二进制补码表示的整数;最小值是-128zhi(-2^7);最大值是127(2^7-1);默认......
  • JavaScript 中的闭包和事件委托
    闭包(Closures)闭包是JavaScript中一个非常强大的特性,它允许函数访问其外部作用域中的变量,即使在该函数被调用时,外部作用域已经执行完毕。闭包可以帮助我们实现数据的私有化、封装和模块化,使代码更简洁、易读和可维护。闭包的定义简单来说,闭包是指有权访问另一个函数作用域......