我正在做一些实验,试图在实践中理解线程。请看下面的代码片段:它是一个main
函数,它产生一个侦听端口2020的线程。这个线程反过来侦听这个端口上的连接,并且每当客户端连接时,它产生另一个< / em>线程稍微休眠然后写入套接字。
class MyRunner(s:Socket,num:Int) extends Runnable{
val r = scala.util.Random
def run(): Unit ={
if(num == 5 )
Thread.sleep(15000)
else
Thread.sleep(1000)
s.getOutputStream.write(s"My number is ${num}! \n".getBytes)
s.getOutputStream.close()
}
}
// this thread opens a MyRunner thread on each new connection
class MyService extends Runnable{
val serverSocket = new ServerSocket(2020)
var num = 0
def run():Unit = {
while(true){
val socket = serverSocket.accept()
num += 1
(new MyRunner(socket,num)).run()
}
}
}
// main function
object app {
def main(args: Array[String]) {
(new MyService).run
}
}
现在我正在测试这个设置。这就是我所做的:我打开了两个终端窗口,每个窗口都输入了命令:
$ for i in `seq 1 5`; do netcat localhost 2020; done
事情是,当在其中一个终端上达到数字5(根据条件)时,另一个不继续运行。两个客户端都会停止,直到15秒的超时结束。
我想知道我做错了什么,因为我认为使用线程的整个目的是拥有非阻塞应用程序,即使对方忙,也可以为客户端提供服务。
P.S。:我在具有4个可用处理器的VirtualBox VM上运行它(在我的主机中总共8个)。
答案 0 :(得分:7)
您的应用不会创建任何主题。创建一个这样的线程:
Thread serverThread = new Thread(new MyService());
serverThread.start();
thread.start()
方法是库提供的低级方法,供您在创建新线程时调用代码。
serverThread.run()
方法是您的代码为库提供的方法,用于在新线程中调用。
额外信用:了解如何使用线程池(例如java.util.concurrent.ThreadPoolExecutor
),而不是为每个客户端连接创建和销毁新线程。创建和销毁线程非常昂贵。