Java多线程问题--当i++遇上System.out.println()

本文探讨了在Java多线程环境下System.out.println(i++)操作的线程安全性,通过分析i++操作的底层实现,揭示了其在并发场景下可能引发的问题,并提供了一个测试示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文内容部分引自《Java多线程编程核心技术》,感谢作者!!!

代码地址:https://github.com/xianzhixianzhixian/thread.git

首先我们看看System.out.println()的源码,输出x的时候是由synchronized代码块包裹着的,那么System.out.println(i++)是否就是线程安全的呢?

然而并不是的,下面来说明原因:

在某些JVM中,i++的操作分为以下三步(i--同样):

1、取得原有i的值。

2、计算i+1。

3、对i进行赋值。

在这三个步骤中,如果有多个线程同时访问,那么一定会出现非线程安全问题。所以System.out.println(i++)有概率出现非线程安全问题

package thread.stdout.iplusplus;

/**
 * 测试System.out.println(i++)出现非线程安全问题
 * @author: xianzhixianzhixian
 * @date: 2018-12-10 21:48
 */
public class MyThread extends Thread {
    private int i = 5;
    @Override
    public void run() {
        super.run();
        System.out.println("i="+(i++)+" threadName="+Thread.currentThread().getName());
    }
}

 

第二章 基本程序设计 1、实验名:基本程序的实现 1.1在控制台中求两个实数的和,要求:通过键盘输入任意两个实数,求出它们的和并输出。 1.2 编写程序,实现从键盘读取三个数值,并显示他们的平均值。 2、实验名:算术运算练习 2.1 程序清单 public class Example1{ public static void main(String[ ] args){ int i=0; double x=2.3; System.out.println(“结果1:”+(--i+i+i++)); System.out.println(“结果2:”+(i+++i)); i+=i+(i=4); System.out.println(“结果3:”+i); i=3+3*2%i--; System.out.println(“结果4:”+i); x+=1.2*3+x++; System.out.println(“结果5:”+x); x=x%3+4*2+x--; System.out.println(“结果6:”+x); } } 运行该程序,观察++--运算的运算优先级别。形式i++++i有什么区别。描述程序中main( )方法的语句i+=i+(i=4);的运算过程? 2.2 程序清单 读下列程序,理解不同数据类型变量的声明,写出其输出结果并上机运行验证。 public class SHIYAN2_1 { public static void main(String[ ] args){ byte b=0x55; short s=0x55ff; int i=1000000; long l=0xffffL; char c=’a’; float f=0.23F; double d=0.7E-3; boolean B=true; String S=”这是字符串类数据类型”; System.out.println(“字节型变量b=”+b); System.out.println(“短整型变量s=”+s); System.out.println(“整型变量 i=”+i); System.out.println(“长整型变量 l=”+l); System.out.println(“字符型变量 c=”+c); System.out.println(“浮点型变量 f=”+f); System.out.println(“双精度变量 d=”+d); System.out.println(“布尔型变量 B=”+B); System.out.println(“字符串类对象 S=”+s); } } 2.3分析下列程序,了解变量的使用范围,修改程序使之能成功运行。 public class SHIYAN2_2{ int i=10; public static void main(String[ ] args){ { int k=10; System.out.println(“i=”+i); System.out.println(“k=”+k); } System.out.println(“i=”+i); System.out.println(“k=”+k); } } 2.4请在控制台输入一个大写字母,并将该大写字母转换为小写字母并输出。
最新发布
05-30
<think>好的,我需要帮助用户理解Java程序设计中的基本概念,并完成几个实验。用户提到了变量类型、运算符优先级、数据类型转换、变量作用域,以及具体的实验题目。首先,我需要回顾用户提供的引用内容,看看是否有相关的信息可以利用。引用[1]提到运算符和表达式,引用[3]涉及整除和求余运算,这可能与用户的问题中的运算符优先级和计算有关。不过用户的问题主要集中在Java上,而引用中的例子是Python和C,可能需要调整。首先,用户需要完成几个实验:求两个实数的和、计算三个数的平均值、分析++--的优先级及i+=i+(i=4)的运算过程、不同数据类型变量的声明与输出、变量作用域问题、大写字母转小写。我需要逐一分析每个实验,确保涵盖所有知识点。对于变量类型,Java有基本数据类型如int、double等,以及引用类型。变量作用域涉及块作用域、方法作用域等。运算符优先级方面,++--属于一元运算符,优先级较高,而赋值运算符如+=优先级较低。数据类型转换包括隐式转换和显式强制转换。大写转小写可以通过ASCII码差值或Character类的方法实现。接下来,我需要考虑如何将这些知识点融入实验步骤中。例如,在计算平均值时,需要注意整数除法和浮点数除法的区别。在分析i+=i+(i=4)时,需要理解运算符的结合性和执行顺序,可能涉及表达式的求值顺序,这在Java中是严格从左到右的。变量作用域的问题,可能需要通过示例展示在代码块内部声明的变量无法在外部访问。数据类型转换时,如将double转换为int会导致精度丢失,需要显式强制转换。在编写代码示例时,要确保语法正确,比如使用System.out.println输出,正确声明变量类型。同时,要解释每个步骤的原理,例如使用(char)(ch+32)来转换大小写,因为ASCII中大写和小写相差32。还需要注意用户提到的系统级指令,如数学表达式使用LaTeX格式,引用文献标记。例如,在解释运算符优先级时,可能需要用数学表达式表示运算顺序,如$i +=(i +(i=4))$,并正确标注引用来源。 最后,生成相关问题时要围绕用户提到的知识点,如运算符优先级、数据类型转换、作用域规则等,确保问题具有针对性,帮助用户深化理解。</think>### Java基本程序设计实验详解 --- #### 一、求两个实数的和 **实验目标**:掌握基本数据类型`double`的声明与算术运算 ```java public class SumCalculator { public static void main(String[] args) { double a = 3.14; double b = 2.718; double sum = a + b; System.out.println("Sum: " + sum); // 输出:5.858 } } ``` **关键点**: - `double`类型可表示双精度浮点数 - `+`运算符优先级高于赋值运算符[^1] --- #### 二、计算三个数值的平均值 **实验目标**:理解整数与浮点数运算差异 ```java public class AverageCalculator { public static void main(String[] args) { int x = 10, y = 20, z = 30; double avg = (x + y + z) / 3.0; // 必须使用3.0保证浮点运算 System.out.println("Average: " + avg); // 输出:20.0 } } ``` **数学表达式**: 平均值的计算公式为: $$ \text{avg} = \frac{x + y + z}{3} $$ --- #### 三、运算符优先级分析 **实验目标**:理解`++`/`--`优先级与复合赋值运算 ```java int i = 2; i += i + (i = 4); // 运算过程分解: // 1. 原式等价于 i = i + (i + (i=4)) // 2. 从左到右计算:i初始值2 // 3. 先计算右侧表达式:i + (i=4) → 2 + 4 = 6 // 4. 执行赋值:i = 2 + 6 = 8 System.out.println(i); // 输出8 ``` **优先级规则**: 1. 括号`()` > 单目运算符`++`/`--` > 算术运算符 > 赋值运算符 2. `+=`是右结合运算符[^1] --- #### 四、数据类型转换与输出 **实验目标**:掌握显式/隐式类型转换 ```java public class TypeConversion { public static void main(String[] args) { int numInt = 100; double numDouble = numInt; // 隐式转换 byte numByte = (byte)numInt; // 显式强制转换 System.out.println("Double: " + numDouble); // 100.0 System.out.println("Byte: " + numByte); // 100 } } ``` **类型转换规则**: - 小类型→大类型自动转换(如`int`→`double`) - 大类型→小类型需强制转换(可能丢失精度) --- #### 五、变量作用域问题 **实验目标**:理解块作用域规则 ```java public class ScopeDemo { public static void main(String[] args) { int outer = 10; { int inner = 20; System.out.println(outer); // 合法 } // System.out.println(inner); // 编译错误:inner超出作用域 } } ``` **作用域规则**: - 变量仅在声明它的代码块`{}`内有效 - 外层块变量对内层块可见 --- #### 六、大写字母转小写 **实验目标**:掌握字符运算与ASCII码转换 ```java public class LowercaseConverter { public static void main(String[] args) { char ch = 'A'; char lowercase = (char)(ch + 32); // ASCII码差值法 // 或使用标准方法:Character.toLowerCase(ch) System.out.println(lowercase); // 输出a } } ``` **字符运算原理**: - 大写字母ASCII码范围:$65 \sim 90$(A-Z) - 小写字母ASCII码范围:$97 \sim 122$(a-z) - 转换公式:$lower = upper + 32$ --- ### 相关问题 1. 如何防止Java中的整数除法导致精度丢失? 2. `i++`与`++i`在表达式中的具体区别是什么? 3. Java中`final`关键字如何影响变量作用域? 4. 为什么`byte`类型的强制转换可能产生数据溢出? 5. 如何实现字符串的大小写转换? 6. Java的运算符优先级与C语言有哪些主要差异?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值