Java 单线程异步处理

Java 单线程异步处理,java,javascript,multithreading,asynchronous,single-threaded,Java,Javascript,Multithreading,Asynchronous,Single Threaded,即使阅读了本书,我仍然对如何在固有的单线程系统上提供异步调用感到困惑。我将解释我迄今为止的理解,并指出我的疑问 我读过的一个例子是描述一个提供异步处理请求的TCP服务器——用户会调用一个方法,例如get(Callback c),稍后会调用回调。现在,我在这里的第一个问题-我们已经有两个系统,一个服务器和一个客户端。这不是我的意思,因为事实上我们至少有两个线程——一个在服务器端,一个在客户端 我读的另一个例子是JavaScript,因为这是使用Node.js的单线程异步系统的最突出的例子。我脑子里

即使阅读了本书,我仍然对如何在固有的单线程系统上提供异步调用感到困惑。我将解释我迄今为止的理解,并指出我的疑问

我读过的一个例子是描述一个提供异步处理请求的TCP服务器——用户会调用一个方法,例如
get(Callback c)
,稍后会调用回调。现在,我在这里的第一个问题-我们已经有两个系统,一个服务器和一个客户端。这不是我的意思,因为事实上我们至少有两个线程——一个在服务器端,一个在客户端

我读的另一个例子是JavaScript,因为这是使用
Node.js
的单线程异步系统的最突出的例子。我脑子里想不透的,也许是用Java术语思考的,是这样的:如果我执行下面的代码(为错误的,可能是糟糕的语法道歉):

对读取文件的调用执行(sth)并返回,允许我的其余函数执行。既然只有一个线程,即执行我的函数的线程,那么同一个线程(也是唯一一个执行我的东西的线程)究竟如何从磁盘读取字节呢

基本上,在我看来,我缺少了一些底层机制,这些机制就像某种循环调度程序一样,本质上是单线程的,可能会将任务拆分为较小的任务,或者调用多线程组件,从而生成线程并读取文件

提前感谢您的所有评论,并在途中指出我的错误

更新:感谢所有回复。帮助我解决这一问题的其他好消息来源如下:

  • (.NET)
  • (计时器的本质)

  • 真正的答案是,这取决于你所说的“单线程”是什么意思

    多任务处理有两种方法:协作和中断驱动。Cooperative是您引用的另一个StackOverflow项所描述的,它要求例程显式地放弃处理器的所有权,以便它可以做其他事情。事件驱动系统通常是这样设计的。这样做的好处是,它更易于管理,并且避免了对数据的访问冲突的大部分风险,因为在任何时候只有一块代码在执行。缺点是,因为一次只做一件事,所以所有的事情都必须设计成能够相当快地执行,或者被分解成块(通过显式暂停,如
    yield()
    调用),否则系统将看起来冻结,直到事件完全处理完毕

    另一种方法——线程或进程——主动地让处理器停止运行代码块,在执行其他操作时暂停它们。这一点的实现要复杂得多,而且在编码时需要更加小心,因为您现在有同时访问共享数据结构的风险,但功能更强大,而且(正确地完成)更健壮,响应更快


    是的,这两种情况都涉及到一个调度程序。在前一个版本中,调度程序只是在旋转,直到事件到达(从操作系统和/或运行时环境传递,隐式地是另一个线程或进程),并在处理下一个到达的事件之前调度该事件

    我在JavaScript中的想法是,有一个队列保存事件。在旧的Java生产者/消费者说法中,有一个消费者线程从这个队列中提取内容,并执行注册以接收当前事件的每个函数。异步调用(AJAX请求完成)、超时或鼠标事件等事件一发生就会被推送到队列中。单个“使用者”线程将它们从队列中拉出来,定位任何感兴趣的函数,然后执行它们,直到调用完当前事件上注册的所有函数,它才能进入下一个事件。因此,如果您有一个永远不会完成的处理程序,那么队列就会被填满——这被称为“阻塞”

    系统有多个线程(至少有一个生产者和消费者),因为某些东西会生成要在队列上运行的事件,但作为事件处理程序的作者,您需要知道,如果您进入一个紧密循环,事件是在单个线程中处理的,您将锁定唯一的使用者线程并使系统无响应

    在你的例子中:

     function foo(){
        read_file(location, function(fileContents) {
            // called with the fileContents when file is read
        }     
        //do many things more here, potentially for hours
     }
    
    如果您按照您的注释执行,并且可能执行数小时,那么即使文件已被读取,处理文件内容的回调也不会触发数小时。当您点击foo()的最后一个}时,使用者线程就完成了此事件,并可以处理下一个事件,在该事件中,使用者线程将使用文件内容执行已注册的回调


    HTH

    可能存在也可能不存在由挂起的操作隐式启动的后台线程,但它完全不透明,与启动操作本身的JavaScript代码无关。web浏览器(或NodeJS,FTM)中JavaScript线程的核心事件循环是单线程的。那么,在Java脚本中,我从磁盘加载文件的调用将是放置在要处理的队列上的一个事件或一系列事件?但既然是这样,我的代码就不是真正的执行线程,因为只有一个线程,实际上,它只是队列的主循环线程拉取事件。。。因此,如果主线程正在进行事件拉取,那么显然必须有另一个线程正在调度这些事件iu.e。把他们放在队列中,对吗?我不是一个真正的Javascript用户,所以我不能具体回答这个问题。但是请记住,您已经有了一个完整的操作系统,加上浏览器或其他运行Javascript的运行环境。它们有自己的线程/进程与Javascript分时,并且在Ja中有异步操作
     function foo(){
        read_file(location, function(fileContents) {
            // called with the fileContents when file is read
        }     
        //do many things more here, potentially for hours
     }