Scala教程(十八)并发编程详解

 

 

Scala教程(十八)并发编程详解

 

 

1 Scala并发Actor


1.1 创建和启动Actor

  编写Actor并发程序,实现(trait)Actor特征,重写act方法,act方法与Java中的Runnable接口的run方法很相似。

正如不同的线程Actoract方法也是可以并行运行的。

    import scala.actors.Actor
    /*
     * Actor是一种基于事件的轻量级线程,使用Actor则需要关注操作数据的代码结构,因为减少了数据的共享。
     * Actor的主要能力来源于消息传递,而不是采用阻塞调用的处理形式。
     * 如果创建直接或间接扩展 Actor的类,要确保对对象的所有调用都通过消息传递进行。
     * 
     * Actor提供了并发程序与传统的基于锁(比如:Java)结构不同。Actor使我们更容易设计正确、没死锁或争用状况的程序。
     * 编写Actor并发程序,实现(trait)Actor特征,重写act方法,act方法与Java中的Runnable接口的run方法很相似。
     * 正如不同的线程Actor的act方法也是可以并行运行的。
     */
    object FirstActor extends Actor {
      def act(): Unit = {
        // 输出当前线程名称
        println(Thread.currentThread().getName);
        List.range(1, 11).foreach {
          x =>
            println("FirstActor==>" + x); // 输出执结次数
            Thread.sleep(1000); // 程序1秒后再执行
        }
      }
    }
    
    object SecondActor extends Actor {
      def act(): Unit = {
        // 输出当前线程名称
        println(Thread.currentThread().getName);
        List.range(1, 11).foreach {
          x =>
            println("SecondActor:==>" + x); // 输出执结次数
            Thread.sleep(1000); // 程序1秒后再执行
        }
      }
    }
    
    object HelloActor {
      def main(args: Array[String]): Unit = {
        // start方式启动多线程
        FirstActor.start();
        SecondActor.start();
      }
    }
 
 

1.2 发送/接收消息

Actor是一个处理异步消息对象。你向某个Actor发送消息,该Actor处理消息,或许还会向其它Actor发送消息做进一步处理。

消息可以是任何对象,发送消息的语法:actor ! message

    import scala.actors.Actor
    import scala.actors.Actor.actor
    import scala.actors.Actor.receive
    
    // 定义ActorMessage对象,继承Actor
    object Actor_Message extends Actor {
      // 重写act方法
      def act(): Unit = {
        /*
         *  循环遍历receive - "邮箱" 将msg消息直接打印输出。
         *  receive偏函数,调用apply方法,调用isDefinedAt判断模式匹配中是否有定义case匹配,如果有case匹配,则返回true
         *  没有对应的case匹配不会报错,会被忽略掉。receive所在的Actor会一直处理阻塞(一直等待处理)状态。
         */
        while (true) {
          receive {
            case msg => println("Message content Actor from inbox:" + msg);
          }
        }
      }
    }
    // 匿名actor
    object ActorMessage {
      def main(args: Array[String]): Unit = {
        // 匿名actor立即执行
        val actorMessage = actor {
          while (true) {
            // 偏函数代码块
            receive {
              // 模式匹配
              case msg: Double => println("Double Number from inbox:" + msg);
              case _           => println("Something Unkown");
            }
          }
        }
    
        // 命令Actor,函数调用
        Actor_Message.start();
        /*
         *  发送异步消息,语法:actor ! message
         *  执行结果:Message content Actor from inbox:Hadoop
         */
        Actor_Message ! "Hadoop";
    
        /*
         *  发送PI
         *  执行结果:Double Number from inbox:3.141592653589793
         */
        actorMessage ! Math.PI;
        // 执行结果:Something Unkown
        actorMessage ! "Spark"
      }
    }

1.3 消息模式匹配

偏函数中接收case class对象类型的信息。通过模式匹配直接提取内容的信息。

    import scala.actors.Actor
    import scala.actors.Actor.self
    
    // 定义case Person类
    case class Person(name: String, age: Int);
    class HelloActor extends Actor {
      def act(): Unit = {
        while (true) {
          // 偏函数代码块
          // 每个case都是线行的,不是并行的,不会存资源竞争的情况
          receive {
            // 模式匹配,可以从case class提取内容,提取方法从apply中
            case Person(name, age) =>
              // 执行结果:Name==>Spark:Age==>6
              println("Name==>" + name + ":Age==>" + age);
              sender ! "Echo!!!"; // 向主线程发送消息
    
            // 其它匹配项,需要编写为无关的“邮件”占满“邮箱”进行其它处理。
            case _ => println("Something else...")
          }
        }
      }
    }
    
    object ActorWithCaseClass {
      def main(args: Array[String]): Unit = {
        val hiActor = new HelloActor();
        // 启动多线程
        hiActor.start();
        // 发送消息
        hiActor ! Person("Spark", 6);
        // 接收返回的消息,执行结果:msg==>Echo!!!
        self.receive { case msg => println("msg==>" + msg) };
      }
    }

1.4 react关键字

react:不返回具体的内容,其实返回的值是Nothing,该类型表示非正常退出。

每次对react的调用都会返回Nothing,从而清栈。下一个actor,重用当前actor所在的线程。

    import scala.actors.Actor;
    import scala.actors.Actor._;
    import java.net.InetAddress;
    import java.net.UnknownHostException;
    
    case class Net(name: String, actor: Actor);
    
    object NameResolver extends Actor {
      def act(): Unit = {
        /*
         *  react:不返回具体的内容,其实返回的值是Nothing,该类型表示非正常退出。
         *  下次再调用自己本身act()方法,形成无限递归循环,这个递归不会占用很大的栈空间。
         *  每次对react的调用都会返回Nothing,从而清栈。
         *  下一个actor,重用当前actor所在的线程。
         */
        react {
          // case模式匹配
          case Net(name, actor) =>
            sender ! getIp(name);
            act(); // 自已调用本身实现在递归循环
          case "EXIT" =>
            println("Name resolver exiting.");
            act(); // 自已调用本身实现在递归循环   
          case msg =>
            println("Unhandled message:" + msg);
            act(); // 自已调用本身实现在递归循环
        }
      }
    
      // 通过域名获取Ip地址
      def getIp(name: String): Option[InetAddress] = {
        try {
          // 输出Ip地址
          println(InetAddress.getByName(name));
          // 解析的结果返回Some
          return Some(InetAddress.getByName(name));
        } catch {
          // 抛出异常,返回None
          case _: UnknownHostException => None;
        }
      }
    }
    
    object ActorMoreEffective {
      def main(args: Array[String]): Unit = {
        // 启动线程 
        NameResolver.start();
        // 发送消息,自引用传递self
        NameResolver ! Net("www.baidu.com", self)
        // 接收返回的消息,1秒后超时,执行结果:Some(www.baidu.com/61.135.169.121)
        println(self.receiveWithin(1000) { case x => x });
      }
    }

1.5 loop关键字

loop关键字可以制作一个无穷循环。

    import scala.actors.Actor;
    import scala.actors.Actor._;
    import java.net.InetAddress;
    import java.net.UnknownHostException;
    
    case class Net(name: String, actor: Actor);
    
    object NameResolver extends Actor {
      def act(): Unit = {
        /*
         *  无限循环
         *  loopWhile可以添加循环条件,如:loopWhile(count < max)
         */
        loop {
          react {
            // case模式匹配
            case Net(name, actor) =>
              sender ! getIp(name);
            case msg =>
              println("Unhandled message:" + msg);
          }
        }
      }
    
      // 通过域名获取Ip地址
      def getIp(name: String): Option[InetAddress] = {
        try {
          // 输出Ip地址
          println(InetAddress.getByName(name));
          // 解析的结果返回Some
          return Some(InetAddress.getByName(name));
        } catch {
          // 抛出异常,返回None
          case _: UnknownHostException => None;
        }
      }
    }
    
    object ActorMoreEffective {
      def main(args: Array[String]): Unit = {
        // 启动线程 
        NameResolver.start();
        // 发送消息,自引用传递self
        NameResolver ! Net("www.baidu.com", self)
        // 接收返回的消息,1秒后超时,执行结果:Some(www.baidu.com/61.135.169.121)
        println(self.receiveWithin(1000) { case x => x });
      }
    }


    --以上为Scala并发编程详解,谢谢大家对我的关注。

                                                                                                                                                                                      ——厚积薄发(yuanxw)

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值