We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Port not being released after stopping threaded holoviz panel app server
Closing a threaded panel app holds on to the port it started on. This is different behavior than closing an app initialized without threading.

```
usgs_logo = pn.panel('../assets/usgs_logo.png', height=130)

column = pn.Column(usgs_logo)

app = column.show(port=8889)

app.stop()
```

Port 8889 is released.

```
app = row.show(port=8889, threaded=True)

app.stop()
```
Port 8889 is not released.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `panel/io/server.py`
Content:
```
1 """
2 Utilities for creating bokeh Server instances.
3 """
4 from __future__ import absolute_import, division, unicode_literals
5 
6 import signal
7 import threading
8 
9 from functools import partial
10 
11 from bokeh.server.server import Server
12 
13 from .state import state
14 
15 
16 #---------------------------------------------------------------------
17 # Private API
18 #---------------------------------------------------------------------
19 
20 def _origin_url(url):
21     if url.startswith("http"):
22         url = url.split("//")[1]
23     return url
24 
25 
26 def _server_url(url, port):
27     if url.startswith("http"):
28         return '%s:%d%s' % (url.rsplit(':', 1)[0], port, "/")
29     else:
30         return 'http://%s:%d%s' % (url.split(':')[0], port, "/")
31 
32 #---------------------------------------------------------------------
33 # Public API
34 #---------------------------------------------------------------------
35 
36 def get_server(panel, port=0, websocket_origin=None, loop=None,
37                show=False, start=False, **kwargs):
38     """
39     Returns a Server instance with this panel attached as the root
40     app.
41 
42     Arguments
43     ---------
44     port: int (optional, default=0)
45       Allows specifying a specific port
46     websocket_origin: str or list(str) (optional)
47       A list of hosts that can connect to the websocket.
48 
49       This is typically required when embedding a server app in
50       an external web site.
51 
52       If None, "localhost" is used.
53     loop : tornado.ioloop.IOLoop (optional, default=IOLoop.current())
54       The tornado IOLoop to run the Server on
55     show : boolean (optional, default=False)
56       Whether to open the server in a new browser tab on start
57     start : boolean(optional, default=False)
58       Whether to start the Server
59     kwargs: dict
60       Additional keyword arguments to pass to Server instance
61 
62     Returns
63     -------
64     server : bokeh.server.server.Server
65       Bokeh Server instance running this panel
66     """
67     from tornado.ioloop import IOLoop
68     opts = dict(kwargs)
69     if loop:
70         loop.make_current()
71         opts['io_loop'] = loop
72     else:
73         opts['io_loop'] = IOLoop.current()
74 
75     if websocket_origin:
76         if not isinstance(websocket_origin, list):
77             websocket_origin = [websocket_origin]
78         opts['allow_websocket_origin'] = websocket_origin
79 
80     server_id = kwargs.pop('server_id', None)
81     server = Server({'/': partial(panel._modify_doc, server_id)}, port=port, **opts)
82     if server_id:
83         state._servers[server_id] = (server, panel, [])
84 
85     if show:
86         def show_callback():
87             server.show('/')
88         server.io_loop.add_callback(show_callback)
89 
90     def sig_exit(*args, **kwargs):
91         server.io_loop.add_callback_from_signal(do_stop)
92 
93     def do_stop(*args, **kwargs):
94         server.io_loop.stop()
95 
96     try:
97         signal.signal(signal.SIGINT, sig_exit)
98     except ValueError:
99         pass # Can't use signal on a thread
100 
101     if start:
102         server.start()
103         try:
104             server.io_loop.start()
105         except RuntimeError:
106             pass
107     return server
108 
109 
110 class StoppableThread(threading.Thread):
111     """Thread class with a stop() method."""
112 
113     def __init__(self, io_loop=None, timeout=1000, **kwargs):
114         from tornado import ioloop
115         super(StoppableThread, self).__init__(**kwargs)
116         self._stop_event = threading.Event()
117         self.io_loop = io_loop
118         self._cb = ioloop.PeriodicCallback(self._check_stopped, timeout)
119         self._cb.start()
120 
121     def _check_stopped(self):
122         if self.stopped:
123             self._cb.stop()
124             self.io_loop.stop()
125 
126     def stop(self):
127         self._stop_event.set()
128 
129     @property
130     def stopped(self):
131         return self._stop_event.is_set()
132
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/panel/io/server.py b/panel/io/server.py
--- a/panel/io/server.py
+++ b/panel/io/server.py
@@ -122,6 +122,15 @@
         if self.stopped:
             self._cb.stop()
             self.io_loop.stop()
+    
+    def run(self):
+        try:
+            if self._target:
+                bokeh_server = self._target(*self._args, **self._kwargs)
+        finally:
+            if isinstance(bokeh_server, Server):
+                bokeh_server.stop()
+            del self._target, self._args, self._kwargs
 
     def stop(self):
         self._stop_event.set()

{"golden_diff": "diff --git a/panel/io/server.py b/panel/io/server.py\n--- a/panel/io/server.py\n+++ b/panel/io/server.py\n@@ -122,6 +122,15 @@\n         if self.stopped:\n             self._cb.stop()\n             self.io_loop.stop()\n+    \n+    def run(self):\n+        try:\n+            if self._target:\n+                bokeh_server = self._target(*self._args, **self._kwargs)\n+        finally:\n+            if isinstance(bokeh_server, Server):\n+                bokeh_server.stop()\n+            del self._target, self._args, self._kwargs\n \n     def stop(self):\n         self._stop_event.set()\n", "issue": "Port not being released after stopping threaded holoviz panel app server\nClosing a threaded panel app holds on to the port it started on. This is different behavior than closing an app initialized without threading.\r\n\r\n```\r\nusgs_logo = pn.panel('../assets/usgs_logo.png', height=130)\r\n\r\ncolumn = pn.Column(usgs_logo)\r\n\r\napp = column.show(port=8889)\r\n\r\napp.stop()\r\n```\r\n\r\nPort 8889 is released.\r\n\r\n```\r\napp = row.show(port=8889, threaded=True)\r\n\r\napp.stop()\r\n```\r\nPort 8889 is not released.\n", "before_files": [{"content": "\"\"\"\nUtilities for creating bokeh Server instances.\n\"\"\"\nfrom __future__ import absolute_import, division, unicode_literals\n\nimport signal\nimport threading\n\nfrom functools import partial\n\nfrom bokeh.server.server import Server\n\nfrom .state import state\n\n\n#---------------------------------------------------------------------\n# Private API\n#---------------------------------------------------------------------\n\ndef _origin_url(url):\n    if url.startswith(\"http\"):\n        url = url.split(\"//\")[1]\n    return url\n\n\ndef _server_url(url, port):\n    if url.startswith(\"http\"):\n        return '%s:%d%s' % (url.rsplit(':', 1)[0], port, \"/\")\n    else:\n        return 'http://%s:%d%s' % (url.split(':')[0], port, \"/\")\n\n#---------------------------------------------------------------------\n# Public API\n#---------------------------------------------------------------------\n\ndef get_server(panel, port=0, websocket_origin=None, loop=None,\n               show=False, start=False, **kwargs):\n    \"\"\"\n    Returns a Server instance with this panel attached as the root\n    app.\n\n    Arguments\n    ---------\n    port: int (optional, default=0)\n      Allows specifying a specific port\n    websocket_origin: str or list(str) (optional)\n      A list of hosts that can connect to the websocket.\n\n      This is typically required when embedding a server app in\n      an external web site.\n\n      If None, \"localhost\" is used.\n    loop : tornado.ioloop.IOLoop (optional, default=IOLoop.current())\n      The tornado IOLoop to run the Server on\n    show : boolean (optional, default=False)\n      Whether to open the server in a new browser tab on start\n    start : boolean(optional, default=False)\n      Whether to start the Server\n    kwargs: dict\n      Additional keyword arguments to pass to Server instance\n\n    Returns\n    -------\n    server : bokeh.server.server.Server\n      Bokeh Server instance running this panel\n    \"\"\"\n    from tornado.ioloop import IOLoop\n    opts = dict(kwargs)\n    if loop:\n        loop.make_current()\n        opts['io_loop'] = loop\n    else:\n        opts['io_loop'] = IOLoop.current()\n\n    if websocket_origin:\n        if not isinstance(websocket_origin, list):\n            websocket_origin = [websocket_origin]\n        opts['allow_websocket_origin'] = websocket_origin\n\n    server_id = kwargs.pop('server_id', None)\n    server = Server({'/': partial(panel._modify_doc, server_id)}, port=port, **opts)\n    if server_id:\n        state._servers[server_id] = (server, panel, [])\n\n    if show:\n        def show_callback():\n            server.show('/')\n        server.io_loop.add_callback(show_callback)\n\n    def sig_exit(*args, **kwargs):\n        server.io_loop.add_callback_from_signal(do_stop)\n\n    def do_stop(*args, **kwargs):\n        server.io_loop.stop()\n\n    try:\n        signal.signal(signal.SIGINT, sig_exit)\n    except ValueError:\n        pass # Can't use signal on a thread\n\n    if start:\n        server.start()\n        try:\n            server.io_loop.start()\n        except RuntimeError:\n            pass\n    return server\n\n\nclass StoppableThread(threading.Thread):\n    \"\"\"Thread class with a stop() method.\"\"\"\n\n    def __init__(self, io_loop=None, timeout=1000, **kwargs):\n        from tornado import ioloop\n        super(StoppableThread, self).__init__(**kwargs)\n        self._stop_event = threading.Event()\n        self.io_loop = io_loop\n        self._cb = ioloop.PeriodicCallback(self._check_stopped, timeout)\n        self._cb.start()\n\n    def _check_stopped(self):\n        if self.stopped:\n            self._cb.stop()\n            self.io_loop.stop()\n\n    def stop(self):\n        self._stop_event.set()\n\n    @property\n    def stopped(self):\n        return self._stop_event.is_set()\n", "path": "panel/io/server.py"}], "after_files": [{"content": "\"\"\"\nUtilities for creating bokeh Server instances.\n\"\"\"\nfrom __future__ import absolute_import, division, unicode_literals\n\nimport signal\nimport threading\n\nfrom functools import partial\n\nfrom bokeh.server.server import Server\n\nfrom .state import state\n\n\n#---------------------------------------------------------------------\n# Private API\n#---------------------------------------------------------------------\n\ndef _origin_url(url):\n    if url.startswith(\"http\"):\n        url = url.split(\"//\")[1]\n    return url\n\n\ndef _server_url(url, port):\n    if url.startswith(\"http\"):\n        return '%s:%d%s' % (url.rsplit(':', 1)[0], port, \"/\")\n    else:\n        return 'http://%s:%d%s' % (url.split(':')[0], port, \"/\")\n\n#---------------------------------------------------------------------\n# Public API\n#---------------------------------------------------------------------\n\ndef get_server(panel, port=0, websocket_origin=None, loop=None,\n               show=False, start=False, **kwargs):\n    \"\"\"\n    Returns a Server instance with this panel attached as the root\n    app.\n\n    Arguments\n    ---------\n    port: int (optional, default=0)\n      Allows specifying a specific port\n    websocket_origin: str or list(str) (optional)\n      A list of hosts that can connect to the websocket.\n\n      This is typically required when embedding a server app in\n      an external web site.\n\n      If None, \"localhost\" is used.\n    loop : tornado.ioloop.IOLoop (optional, default=IOLoop.current())\n      The tornado IOLoop to run the Server on\n    show : boolean (optional, default=False)\n      Whether to open the server in a new browser tab on start\n    start : boolean(optional, default=False)\n      Whether to start the Server\n    kwargs: dict\n      Additional keyword arguments to pass to Server instance\n\n    Returns\n    -------\n    server : bokeh.server.server.Server\n      Bokeh Server instance running this panel\n    \"\"\"\n    from tornado.ioloop import IOLoop\n    opts = dict(kwargs)\n    if loop:\n        loop.make_current()\n        opts['io_loop'] = loop\n    else:\n        opts['io_loop'] = IOLoop.current()\n\n    if websocket_origin:\n        if not isinstance(websocket_origin, list):\n            websocket_origin = [websocket_origin]\n        opts['allow_websocket_origin'] = websocket_origin\n\n    server_id = kwargs.pop('server_id', None)\n    server = Server({'/': partial(panel._modify_doc, server_id)}, port=port, **opts)\n    if server_id:\n        state._servers[server_id] = (server, panel, [])\n\n    if show:\n        def show_callback():\n            server.show('/')\n        server.io_loop.add_callback(show_callback)\n\n    def sig_exit(*args, **kwargs):\n        server.io_loop.add_callback_from_signal(do_stop)\n\n    def do_stop(*args, **kwargs):\n        server.io_loop.stop()\n\n    try:\n        signal.signal(signal.SIGINT, sig_exit)\n    except ValueError:\n        pass # Can't use signal on a thread\n\n    if start:\n        server.start()\n        try:\n            server.io_loop.start()\n        except RuntimeError:\n            pass\n    return server\n\n\nclass StoppableThread(threading.Thread):\n    \"\"\"Thread class with a stop() method.\"\"\"\n\n    def __init__(self, io_loop=None, timeout=1000, **kwargs):\n        from tornado import ioloop\n        super(StoppableThread, self).__init__(**kwargs)\n        self._stop_event = threading.Event()\n        self.io_loop = io_loop\n        self._cb = ioloop.PeriodicCallback(self._check_stopped, timeout)\n        self._cb.start()\n\n    def _check_stopped(self):\n        if self.stopped:\n            self._cb.stop()\n            self.io_loop.stop()\n    \n    def run(self):\n        try:\n            if self._target:\n                bokeh_server = self._target(*self._args, **self._kwargs)\n        finally:\n            if isinstance(bokeh_server, Server):\n                bokeh_server.stop()\n            del self._target, self._args, self._kwargs\n\n    def stop(self):\n        self._stop_event.set()\n\n    @property\n    def stopped(self):\n        return self._stop_event.is_set()\n", "path": "panel/io/server.py"}]}