Scala中的IO操作及ArrayBuffer线程安全问题

简介: Scala中的IO操作及ArrayBuffer线程安全问题处理

通过Scala对文件进行读写操作在实际业务中应用也比较多,这里介绍几种常用的方式,直接上代码:

1.从文件中读取内容

object Main {
  
  def loadData(): Array[String] = {
    var bs: BufferedSource = null
    var in: InputStream = null
    try {
      in = Main.getClass.getClassLoader.getResourceAsStream("data.txt")
      if (in == null) {
        in = new FileInputStream(new File("data.txt"))
      }
      bs = new BufferedSource(in)
      bs.getLines().toArray
    } finally {
      bs.close()
    }
  }
  
  //直接通过scala.io.Source进行读取
  def testSource(): Unit = {
    Source.fromFile("data.txt").foreach(println)
  }

}

2.向文件中写内容

def write(): Unit ={
     //调用的就是java中的io类
    val writer = new PrintWriter(new File("write.txt" ))
    writer.write("scala write")
    writer.close()
}

除了上述读写方式,也可以从"屏幕"上读取用户输入的指令来处理程序:

import scala.io. StdIn
def printIn(): Unit = {
    print("please enter number :")
    val line = StdIn.readLine()
    println(s"number is : $line")
}

Scala ArrayBuffer线程安全问题

相信使用Scala进行应用开发时,ArrayBuffer是经常使用的数组。对ArrayBuffer进行新增元素时,通常使用方法:+=。但是该方法并非线程安全,如果在多线程环境使用该方法,由于并发问题,很容报索引越界异常。

下述模拟多线程向定义的ArrayBuffer中并发插入100个元素:

def arrBuffer(): Unit = {
   //默认初始容量为16
   val arrayBuffer = new ArrayBuffer[Int]()

   val executors = Executors.newFixedThreadPool(100)

   for (i <- 1 to 100) {
     executors.execute(new Runnable {
       override def run(): Unit = {
         arrayBuffer += i
       }
     })
   }

   executors.shutdown()
 }

执行上述程序,报出类似如下的索引越界问题:

java.lang.ArrayIndexOutOfBoundsException: 32
    at scala.collection.mutable.ArrayBuffer.$plus$eq(ArrayBuffer.scala:85)
    at Main$$anonfun$main$1$$anon$1.run(Main.scala:24)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)

来看一下ArrayBuffer的+=实现源码:

//初始容量
protected def initialSize: Int = 16
//array默认长度为16
protected var array: Array[AnyRef] = new Array[AnyRef](math.max(initialSize, 1))
//元素个数,默认0
protected var size0: Int = 0
  
def +=(elem: A): this.type = {
    ensureSize(size0 + 1)
    array(size0) = elem.asInstanceOf[AnyRef]
    size0 += 1
    this
}

val arrayBuffer = new ArrayBuffer[Int]():初始容量为16,并发情况下当array长度为16,但是size0已经大于16,并且array没有及时扩容时,就会报索引越界。

所以,在并发环境下,要注意调用该方法时的线程安全问题,比如利用synchronized做锁处理。

这里只是以ArrayBuffer为例,对于Scala中其他的集合使用时也要注意,防止类似问题的出现影响程序的正常运行。

相关文章
|
7月前
|
算法 数据处理 Python
Python并发编程:解密异步IO与多线程
本文将深入探讨Python中的并发编程技术,重点介绍异步IO和多线程两种常见的并发模型。通过对比它们的特点、适用场景和实现方式,帮助读者更好地理解并发编程的核心概念,并掌握在不同场景下选择合适的并发模型的方法。
|
7月前
|
存储 Linux API
Linux应用开发基础知识——文件IO操作(三)
Linux应用开发基础知识——文件IO操作(三)
88 2
Linux应用开发基础知识——文件IO操作(三)
|
7月前
|
数据采集 异构计算
LabVIEW编程LabVIEW开发高级数据采集技术 操作数字IO 例程与相关资料
LabVIEW编程LabVIEW开发高级数据采集技术 操作数字IO 例程与相关资料
96 22
WXM
|
4月前
|
存储 缓存 算法
IO/线程的零拷贝
服务器在提供文件传输功能时,传统实现方式是通过读取磁盘文件内容,将其加载到用户空间的缓冲区,再通过网络 API 发送至客户端,这个过程涉及多次上下文切换和内存拷贝,导致性能下降。
WXM
58 12
|
6月前
|
数据采集 算法 数据处理
Python并发编程:异步IO与多线程的比较与应用
本文探讨了Python中异步IO和多线程两种并发编程模型的优劣及其在实际应用中的适用性。通过比较它们在性能、资源消耗和代码复杂度等方面的差异,分析了不同场景下选择合适的并发模型的策略和方法。
|
6月前
|
缓存 NoSQL Redis
redis管道操作(节省网络IO开销)
pipeline中发送的每个command都会被server立即执行,如果执行失败,将会在此后的响应中得到信息;也就是pipeline并不是表达“所有command都一起成功”的语义,管道中前面命令失败,后面命令不会有影响,继续执行。
54 1
|
5月前
|
数据采集 算法 数据处理
Python中的并发编程:异步IO与多线程对比分析
传统的多线程编程在Python中因为全局解释器锁(GIL)的存在受到限制,导致多线程并不能充分利用多核处理器的优势。本文将探讨Python中的异步IO编程与多线程编程的差异与优劣,并分析适合的应用场景。
|
7月前
|
Java
|
7月前
|
消息中间件 关系型数据库 Kafka
实时计算 Flink版操作报错之在执行任务时遇到了一个IO错误,具体表现为无法从本地主机(localhost)下载文件,该怎么解决
在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。
|
7月前
|
监控 Java
Java一分钟之-NIO:非阻塞IO操作
【5月更文挑战第14天】Java的NIO(New IO)解决了传统BIO在高并发下的低效问题,通过非阻塞方式提高性能。NIO涉及复杂的选择器和缓冲区管理,易出现线程、内存和中断处理的误区。要避免这些问题,可以使用如Netty的NIO库,谨慎设计并发策略,并建立标准异常处理。示例展示了简单NIO服务器,接收连接并发送欢迎消息。理解NIO工作原理和最佳实践,有助于构建高效网络应用。
88 2