for循环内使用wait()方法注意

这篇博客总结了在使用wait()和notify()进行线程通信时,在for循环内部使用if-elseif结构调用wait()方法导致的错误。作者通过示例代码展示了由于没有在wait()后重新判断条件,导致输出结果缺失的情况,并提出了将for循环改为while循环以及修改判断结构的解决方案。

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

     今天用wait()和notify()进行线程通信实现输出12A34B56C.....格式的长字符,写了一段看起来很不成熟的代码,然后还把自己绕晕了= =、原来是因为在for循环里使用if-elseif结构调用wait方法导致出错,找了好久的bug终于反应过来了,为了下次不再犯类似的错误,在这里进行一下总结。

   下面就是我那不太成熟的代码:

//打印字母的线程类
public class PrintAlphabet implements Runnable {
      private MyPrint myprint;

	@Override
	public void run() {
          myprint.printAlphabet();
	}
	public PrintAlphabet(MyPrint myprint) {
		super();
		this.myprint = myprint;
	}
}
 
//打印数字的线程类
public class PrintCount implements Runnable{
	 private MyPrint myprint;
	@Override
	public void run() {
		myprint.printCount();
	}
	public PrintCount(MyPrint myprint) {
		super();
		this.myprint = myprint;
	}
}

 

//打印字母的方法
public synchronized  void printAlphabet(){
			for(;number<78;number++){
			   if(number%3==0){
				   try {
					wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			   }
			   else  if(number%3==1){
				   System.out.println("老大number:"+number+"----->"+countnumber+++"  ");
			   }
			   else  if(number%3==2) {
				   System.out.println("老二number:"+number+"----->"+countnumber+++"  ");
				    notifyAll();
			   }
			   }
		   
	}

//打印数字的方法
public synchronized  void printCount(){
		for(;number<78;number++){
			   if(number%3==1||number%3==2){
				   try {
					wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			   }
			   else  if(number%3==0){
			  System.out.println("老三number:"+number+"----->"+(char) alphabetnumber+++"   ");
			   
			   notifyAll();
			   }
		   }
		}
	

 

运行结果如下:

后面仔细检查发现自己蠢哭了,原来每次回到wait()的地方都没有进行重新判断number的值,而是直接结束了本次循环。所以具体过程应该是这样的:

      首先number等于1打印出老大,然后继续循环打印出老二,当运行到number等于3之后甲线程wait,在乙线程输出来老三,然后调用nitifyAll()唤醒线程甲,但是要先number加一等于4之后线程甲才回到之前wait的地方,但是因为我没有用while重新进行判断,所以执行完wait就直接结束本次循环number又加一等于5,直接跟着打印出了老二,这就解释了上面运行结果为什么缺了老大,继续number加一等于6,此时线程1就wait了。然后又回到第二个线程wait的地方开始运行,还是因为没有重新判断,所以这个时候又直接加一为7,所以线程2也wait了。

  解决办法:1.把for循环改成while循环          

                    2.把if-elseif-结构改成if-if-if结构

 总结: 其实看代码发现,其实我的wait()方法也是放在循环中的,只是因为我用的是for循环,又使用if-elseif结构进行判断,这就导致了每次重新回到了wait的地方都不能继续往下执行,而如果我用while循环就不会出现这种情况了。

 

 

 

<think>好的,我现在需要帮助用户了解如何在Shell脚本中使用for循环。用户之前询问过并发编程,现在转向基础循环结构,可能是在学习脚本编写的基础知识。我需要确保回答清晰、结构合理,并覆盖不同使用场景。 首先,用户的问题是关于for循环使用,因此需要涵盖基本语法、常见用例、不同shell的差异以及注意事项。考虑到用户可能刚接触shell脚本,应该从最简单的例子开始,逐步深入。 用户之前的问题是关于并发的,可能已经有一定基础,但也不能假设太多。需要平衡基础内容和进阶技巧。例如,可以提到如何在for循环中结合并发,比如使用后台执行,这样能衔接之前的知识点。 接下来,我需要检查是否有系统级指令需要注意。用户之前的对话中有提到使用正确的LaTeX格式,但当前问题不涉及数学公式,所以可能不需要。但需要确保代码块格式正确,使用bash语法高亮。 然后,组织内容结构。可以分为基本用法、常见用法、不同shell的差异、结合并发、注意事项等部分。每个部分用示例说明,帮助用户理解。例如,基本语法部分展示数字循环、列表循环和文件遍历。 还要注意用户可能的实际应用场景,比如处理文件、批量操作等,提供相应的例子。例如,重命名文件、处理CSV文件等。此外,提到不同shell的差异很重要,比如bash和zsh在循环语法上的区别,避免用户遇到兼容性问题。 在注意事项部分,需要强调引号的使用、避免空格导致的错误、错误处理等常见陷阱。特别是用户可能在循环中处理带空格的文件名,这时候引号必不可少。 最后,结合用户之前对并发的兴趣,可以补充如何在for循环中实现并行执行,使用&和wait命令,这样既复习了之前的内容,又展示了循环的高级用法。 需要确保语言简洁明了,避免技术术语过多,用中文口语化表达,同时保持专业性。检查所有代码示例的正确性,比如括号是否匹配,语法是否正确。例如,C风格for循环的语法在bash中是有效的,但在其他shell中可能不适用,需要明确指出。 总结,回答的结构应该是从基础到高级,覆盖不同使用场景,提供实用示例,并指出常见错误和注意事项,确保用户能够逐步掌握for循环使用方法。</think>在Shell脚本中使用`for`循环的完整指南如下: --- ### 一、基础语法结构 #### 1. 标准格式(兼容所有Shell) ```bash for 变量 in 项目列表 do # 循环体 done ``` #### 2. C语言风格(仅限Bash) ```bash for ((初始值; 条件判断; 变量变化)) do # 循环体 done ``` --- ### 二、典型使用场景 #### 1. 遍历数字序列 ```bash # 传统方式(适用于所有Shell) for i in 1 2 3 4 5 do echo $i done # 使用seq生成序列 for i in $(seq 1 2 10) # 1到10,步长2 do echo $i done # C风格(仅Bash) for ((i=0; i<5; i++)) do echo "当前值:$i" done ``` #### 2. 遍历文件系统 ```bash # 遍历当前目录所有txt文件 for file in *.txt do echo "处理文件:$file" mv "$file" "${file%.txt}.bak" done # 递归遍历目录(需要Bash 4+) shopt -s globstar for file in **/*.log do echo "找到日志文件:$file" done ``` #### 3. 处理命令输出 ```bash # 遍历进程列表 for pid in $(pgrep nginx) do echo "杀死进程:$pid" kill $pid done # 处理CSV文件内容 for line in $(cat data.csv | tr -d '\r') do IFS=',' read -r col1 col2 <<< "$line" echo "第一列:$col1,第二列:$col2" done ``` --- ### 三、进阶技巧 #### 1. 嵌套循环 ```bash for i in {A..C} do for j in {1..3} do echo "$i$j" done done ``` #### 2. 中断控制 ```bash for file in * do if [[ "$file" == "stop.flag" ]]; then echo "发现停止标志" break # 跳出整个循环 fi if [[ -d "$file" ]]; then continue # 跳过目录处理 fi echo "处理文件:$file" done ``` #### 3. 并行执行(结合后台任务) ```bash max_parallel=3 for i in {1..10} do { echo "任务$i 开始" sleep 1 echo "任务$i 完成" } & # 控制并发数量 if (( $(jobs | wc -l) >= max_parallel )); then wait -n fi done wait ``` --- ### 四、特殊用法 #### 1. 遍历参数列表 ```bash for arg in "$@" do echo "参数:$arg" done ``` #### 2. 字段分割(使用IFS) ```bash IFS=$'\n' # 按换行符分割 for line in $(cat /etc/passwd | head -n 5) do echo "用户记录:$line" done ``` --- ### 五、不同Shell的差异 | 功能 | Bash | Zsh | |----------------------|----------------------|----------------------| | 数字范围 | `{1..5}` | 同Bash | | 序列生成 | 需要`seq`命令 | 内置`{start..end..step}` | | 浮点数循环 | 不支持 | 支持 | | 通配符递归遍历 | 需要`globstar`选项 | 默认支持 | --- ### 六、最佳实践建议 1. **引号使用**: ```bash # 错误示范(遇到带空格文件名会出错) for file in *.log; do rm $file; done # 正确写法 for file in *.log; do rm "$file"; done ``` 2. **性能优化**: - 避免在循环内频繁启动子进程 - 对大列表优先使用`while read`循环 3. **错误处理**: ```bash for config in /etc/*.conf do if ! grep -q "secure" "$config"; then echo "错误:$config 缺少安全配置" >&2 exit 1 fi done ``` --- 通过灵活运用这些方法,可以处理从简单遍历到复杂批量操作的各种需求。建议先使用简单格式确保兼容性,在需要特定功能时再使用Bash的扩展语法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值