scala并发编程Actor(二十四)

  scala 2.10.x版本及之前使用的是内置的Actor。scala 2.11.x版本后将Akka作为并发编程实现。Akka也实现了类似scala Actor的模型,核心概念也是Actor。

概述

  scala的Actor类似于Java中的多线程编程,但却有所不同。scala中的Actor尽可能地避免锁和共享状态,避免多线程并发时出现资源争用的情况,进而提升多线程编程的性能。

Java内置线程模型Scala Actor模型
“共享数据-锁”模型不共享数据
每个object有一个monitor,监视多线程对可变状态的对象资源的访问actor之间通过message通信,复制不可变状态的对象资源的一个副本,基于Actor消息发送、接收机制进行并发编程
加锁的代码用synchronized标识
死锁问题
每个线程内部顺序执行每个actor内部顺序执行

实现步骤

  Scala提供了Actor trait来让我们更方便地进行actor多线程编程,就Actor trait就类似于Java中的Thread和Runnable一样,是基础的多线程基类和接口。

  • 首先调用start()方法启动Actor

  • 调用start()方法后act()方法会被执行

  • actor内部使用receive/react和模式匹配接收消息

  • actor接收消息

    方法说明
    !异步消息,发送方没有返回值
    !?同步消息,发送方等待返回值
    !!异步消息,发送方返回值是Future[Any]

方法操作

actor启动,调用act()方法

import scala.actors.Actor

object ActorTest {
  def main(args: Array[String]): Unit = {
    println("线程 启动!")
    MyActor1.start()
    MyActor2.start()
  }
}

object MyActor1 extends Actor {
  override def act(): Unit = {
    for (i <- 11 to 19) {
      println("actor01---" + i)
      Thread.sleep(500)
    }
  }
}

object MyActor2 extends Actor {
  override def act(): Unit = {
    for (i <- 21 to 29) {
      println("actor02---" + i)
      Thread.sleep(500)
    }
  }
}

可以不间断地接收消息

object ActorTest {
  def main(args: Array[String]): Unit = {
    println("线程 启动!")
    val actor1 = new MyActor1
    actor1.start()
    // 以下为异步消息,不等待返回
    actor1 ! "start"
    actor1 ! "stop"
    println("消息发送完毕!")
  }
}

class MyActor1 extends Actor {
  override def act(): Unit = {
    while (true) { //以下就是偏函数
      receive {
        case "start" => {
          println("启动中...")
          Thread.sleep(500)
          println("启动完成!")
        }
        case "stop" => {
          println("停止中...")
          Thread.sleep(500)
          println("停止完成!")
        }
      }
    }
  }
}

react方式会复用线程,比receive更高效

import scala.actors.Actor

object ActorTest {
  def main(args: Array[String]): Unit = {
    println("线程 启动!")
    val actor1 = new MyActor1
    actor1.start()
    // 以下为异步消息,不等待返回
    actor1 ! "start"
    actor1 ! "stop"
    println("消息发送完毕!")
  }
}

class MyActor1 extends Actor {
  override def act(): Unit = {
    loop {
      react {
        case "start" => {
          println("starting ...")
          Thread.sleep(1000)
          println("started")
        }
        case "stop" => {
          println("stopping ...")
          Thread.sleep(1000)
          println("stopped ...")
        }
      }
    }
  }
}

结合case class发送消息

import scala.actors.Actor

class AppleActor extends Actor {

  def act(): Unit = {
    while (true) {
      receive {
        case "start" => println("starting ...")
        case SyncMsg(id, msg) => {
          println(id + ",sync " + msg)
          Thread.sleep(5000)
          sender ! ReplyMsg(3,"finished")
        }
        case AsyncMsg(id, msg) => {
          println(id + ",async " + msg)
          Thread.sleep(5000)
        }
      }
    }
  }
}

object AppleActor {
  def main(args: Array[String]) {
    val a = new AppleActor
    a.start()
    //异步消息
    a ! AsyncMsg(1, "hello actor")
    println("异步消息发送完成")
    //同步消息
    //val content = a.!?(1000, SyncMsg(2, "hello actor"))
    //println(content)
    val reply = a !! SyncMsg(2, "hello actor")
    println(reply.isSet)
    //println("123")
    val c = reply.apply()
    println(reply.isSet)
    println(c)
  }
}
case class SyncMsg(id : Int, msg: String)
case class AsyncMsg(id : Int, msg: String)
case class ReplyMsg(id : Int, msg: String)

WordCount案例

import java.io.File

import scala.actors.{Actor, Future}
import scala.collection.mutable
import scala.io.Source


class Task extends Actor {

  override def act(): Unit = {
    loop {
      react {
        case SubmitTask(fileName) => {
          val contents = Source.fromFile(new File(fileName)).mkString
          val arr = contents.split("\r\n")
          val result = arr.flatMap(_.split(" ")).map((_, 1)).groupBy(_._1).mapValues(_.length)
          //val result = arr.flatMap(_.split(" ")).map((_, 1)).groupBy(_._1).mapValues(_.foldLeft(0)(_ + _._2))
          sender ! ResultTask(result)
        }
        case StopTask => {
          exit()
        }
      }
    }
  }
}

object WorkCount {
  def main(args: Array[String]) {
    val files = Array("c://words.txt", "c://words.log")

    val replaySet = new mutable.HashSet[Future[Any]]
    val resultList = new mutable.ListBuffer[ResultTask]

    for(f <- files) {
      val t = new Task
      val replay = t.start() !! SubmitTask(f)
      replaySet += replay
    }

    while(replaySet.size > 0){
      val toCumpute = replaySet.filter(_.isSet)
      for(r <- toCumpute){
        val result = r.apply()
        resultList += result.asInstanceOf[ResultTask]
        replaySet.remove(r)
      }
      Thread.sleep(100)
    }
    val finalResult = resultList.map(_.result).flatten.groupBy(_._1).mapValues(x => x.foldLeft(0)(_ + _._2))
    println(finalResult)
  }
}

case class SubmitTask(fileName: String)
case object StopTask
case class ResultTask(result: Map[String, Int])

忠于技术,热爱分享。欢迎关注公众号:java大数据编程,了解更多技术内容。

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

java大数据编程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值