{"id":3789,"date":"2026-03-30T12:47:07","date_gmt":"2026-03-30T12:47:07","guid":{"rendered":"https:\/\/livsycode.com\/?p=3789"},"modified":"2026-04-07T16:43:40","modified_gmt":"2026-04-07T16:43:40","slug":"thread-vs-queue-vs-actor","status":"publish","type":"post","link":"https:\/\/livsycode.com\/swift\/thread-vs-queue-vs-actor\/","title":{"rendered":"Thread vs Queue vs Actor executor in Swift"},"content":{"rendered":"\n<p>Greetings, traveler!<\/p>\n\n\n\n<p>Questions around concurrency often drift into terminology. Thread, queue, executor \u2014 the words sound related, and many explanations blur the boundaries between them. That usually works until the first real bug appears, and then the model falls apart.<\/p>\n\n\n\n<p>A more reliable way to approach this topic is to separate the concepts by responsibility. Each of them answers a different question about how code runs.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Start with the right mental model<\/h2>\n\n\n\n<p>These three concepts live at different levels of abstraction:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>a thread is where code executes<\/li>\n\n\n\n<li>a queue defines how work is scheduled<\/li>\n\n\n\n<li>an actor executor defines where actor-isolated work is allowed to run<\/li>\n<\/ul>\n\n\n\n<p>Once you keep those roles separate, most confusion disappears.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What a thread actually represents<\/h2>\n\n\n\n<p>A thread is a unit of execution managed by the operating system. It has its own call stack and executes instructions sequentially. Threads can be suspended, resumed, and reused by the system scheduler.<\/p>\n\n\n\n<p>In Swift, threads are not a good place to attach meaning to your logic. An async function may suspend at an <code>await<\/code>, release the current thread, and later resume on a different one.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" style=\"color:#f6f6f4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>func loadData() async {\n    print(Thread.current)\n\n    try? await Task.sleep(nanoseconds: 1_000_000_000)\n\n    print(Thread.current)\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki dracula-soft\" style=\"background-color: #282A36\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #F286C4\">func<\/span><span style=\"color: #F6F6F4\"> <\/span><span style=\"color: #62E884\">loadData<\/span><span style=\"color: #F6F6F4\">() <\/span><span style=\"color: #F286C4\">async<\/span><span style=\"color: #F6F6F4\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">    <\/span><span style=\"color: #97E1F1\">print<\/span><span style=\"color: #F6F6F4\">(Thread.current)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">    <\/span><span style=\"color: #F286C4\">try?<\/span><span style=\"color: #F6F6F4\"> <\/span><span style=\"color: #F286C4\">await<\/span><span style=\"color: #F6F6F4\"> Task.<\/span><span style=\"color: #97E1F1\">sleep<\/span><span style=\"color: #F6F6F4\">(<\/span><span style=\"color: #97E1F1\">nanoseconds<\/span><span style=\"color: #F6F6F4\">: <\/span><span style=\"color: #BF9EEE\">1_000_000_000<\/span><span style=\"color: #F6F6F4\">)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">    <\/span><span style=\"color: #97E1F1\">print<\/span><span style=\"color: #F6F6F4\">(Thread.current)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>Running this function often prints different threads before and after suspension. That behavior is expected. The thread is a resource, not a logical owner of your code.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Dispatch queues: scheduling work<\/h2>\n\n\n\n<p>A dispatch queue from Grand Central Dispatch defines how work is executed. It does not execute anything by itself. Instead, it submits blocks to a pool of threads.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" style=\"color:#f6f6f4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>let queue = DispatchQueue(label: \"com.example.serial\")\n\nqueue.async {\n    print(\"Task 1\")\n}\n\nqueue.async {\n    print(\"Task 2\")\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki dracula-soft\" style=\"background-color: #282A36\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #F286C4\">let<\/span><span style=\"color: #F6F6F4\"> queue <\/span><span style=\"color: #F286C4\">=<\/span><span style=\"color: #F6F6F4\"> <\/span><span style=\"color: #97E1F1\">DispatchQueue<\/span><span style=\"color: #F6F6F4\">(<\/span><span style=\"color: #97E1F1\">label<\/span><span style=\"color: #F6F6F4\">: <\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #E7EE98\">com.example.serial<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #F6F6F4\">)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">queue.<\/span><span style=\"color: #97E1F1\">async<\/span><span style=\"color: #F6F6F4\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">    <\/span><span style=\"color: #97E1F1\">print<\/span><span style=\"color: #F6F6F4\">(<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #E7EE98\">Task 1<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #F6F6F4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">queue.<\/span><span style=\"color: #97E1F1\">async<\/span><span style=\"color: #F6F6F4\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">    <\/span><span style=\"color: #97E1F1\">print<\/span><span style=\"color: #F6F6F4\">(<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #E7EE98\">Task 2<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #F6F6F4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>A serial queue guarantees that tasks do not run at the same time. The system may still execute them on different threads.<\/p>\n\n\n\n<p>That distinction matters. A queue controls ordering. It does not guarantee a specific thread.<\/p>\n\n\n\n<p>Concurrent queues relax the ordering:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" style=\"color:#f6f6f4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>let queue = DispatchQueue(label: \"com.example.concurrent\", attributes: .concurrent)\n\nqueue.async {\n    print(\"Task A\")\n}\n\nqueue.async {\n    print(\"Task B\")\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki dracula-soft\" style=\"background-color: #282A36\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #F286C4\">let<\/span><span style=\"color: #F6F6F4\"> queue <\/span><span style=\"color: #F286C4\">=<\/span><span style=\"color: #F6F6F4\"> <\/span><span style=\"color: #97E1F1\">DispatchQueue<\/span><span style=\"color: #F6F6F4\">(<\/span><span style=\"color: #97E1F1\">label<\/span><span style=\"color: #F6F6F4\">: <\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #E7EE98\">com.example.concurrent<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #F6F6F4\">, <\/span><span style=\"color: #97E1F1\">attributes<\/span><span style=\"color: #F6F6F4\">: .concurrent)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">queue.<\/span><span style=\"color: #97E1F1\">async<\/span><span style=\"color: #F6F6F4\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">    <\/span><span style=\"color: #97E1F1\">print<\/span><span style=\"color: #F6F6F4\">(<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #E7EE98\">Task A<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #F6F6F4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">queue.<\/span><span style=\"color: #97E1F1\">async<\/span><span style=\"color: #F6F6F4\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">    <\/span><span style=\"color: #97E1F1\">print<\/span><span style=\"color: #F6F6F4\">(<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #E7EE98\">Task B<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #F6F6F4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>Both tasks may run in parallel, depending on system resources.<\/p>\n\n\n\n<p>The main queue is a special case. It is tied to the main thread, which makes it the right place for UI updates.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Sync, async and barriers in dispatch queues<\/h2>\n\n\n\n<p>Dispatch queues expose a small set of primitives that define how work is submitted and coordinated. The two most commonly used are <code>async<\/code> and <code>sync<\/code>.<\/p>\n\n\n\n<p><code>async<\/code> submits a block and returns immediately. The caller does not wait for completion.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" style=\"color:#f6f6f4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>let queue = DispatchQueue(label: \"com.example.queue\")\n\nqueue.async {\n    print(\"Executed later\")\n}\n\nprint(\"Continues immediately\")\n<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki dracula-soft\" style=\"background-color: #282A36\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #F286C4\">let<\/span><span style=\"color: #F6F6F4\"> queue <\/span><span style=\"color: #F286C4\">=<\/span><span style=\"color: #F6F6F4\"> <\/span><span style=\"color: #97E1F1\">DispatchQueue<\/span><span style=\"color: #F6F6F4\">(<\/span><span style=\"color: #97E1F1\">label<\/span><span style=\"color: #F6F6F4\">: <\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #E7EE98\">com.example.queue<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #F6F6F4\">)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">queue.<\/span><span style=\"color: #97E1F1\">async<\/span><span style=\"color: #F6F6F4\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">    <\/span><span style=\"color: #97E1F1\">print<\/span><span style=\"color: #F6F6F4\">(<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #E7EE98\">Executed later<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #F6F6F4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #97E1F1\">print<\/span><span style=\"color: #F6F6F4\">(<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #E7EE98\">Continues immediately<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #F6F6F4\">)<\/span><\/span>\n<span class=\"line\"><\/span><\/code><\/pre><\/div>\n\n\n\n<p>This pattern is used when work can run independently from the caller.<\/p>\n\n\n\n<p><code>sync<\/code> submits a block and waits until it finishes. Execution of the current context is paused until the block completes.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" style=\"color:#f6f6f4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>queue.sync {\n    print(\"Executed before returning\")\n}\n\nprint(\"Runs after sync block\")<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki dracula-soft\" style=\"background-color: #282A36\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #F6F6F4\">queue.<\/span><span style=\"color: #97E1F1\">sync<\/span><span style=\"color: #F6F6F4\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">    <\/span><span style=\"color: #97E1F1\">print<\/span><span style=\"color: #F6F6F4\">(<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #E7EE98\">Executed before returning<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #F6F6F4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #97E1F1\">print<\/span><span style=\"color: #F6F6F4\">(<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #E7EE98\">Runs after sync block<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #F6F6F4\">)<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>This makes <code>sync<\/code> useful when a result is required before moving forward, though it needs to be used carefully. Calling <code>sync<\/code> on the same serial queue from within one of its tasks leads to a deadlock because the queue waits for itself to finish work that cannot start.<\/p>\n\n\n\n<p>Concurrent queues introduce another tool: barrier blocks. A barrier allows you to temporarily serialize access within a concurrent queue.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" style=\"color:#f6f6f4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>let queue = DispatchQueue(label: \"com.example.concurrent\", attributes: .concurrent)\nvar storage: &#091;Int&#093; = []\n\nqueue.async {\n    storage.append(1)\n}\n\nqueue.async {\n    storage.append(2)\n}\n\nqueue.async(flags: .barrier) {\n    storage.removeAll()\n}\n<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki dracula-soft\" style=\"background-color: #282A36\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #F286C4\">let<\/span><span style=\"color: #F6F6F4\"> queue <\/span><span style=\"color: #F286C4\">=<\/span><span style=\"color: #F6F6F4\"> <\/span><span style=\"color: #97E1F1\">DispatchQueue<\/span><span style=\"color: #F6F6F4\">(<\/span><span style=\"color: #97E1F1\">label<\/span><span style=\"color: #F6F6F4\">: <\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #E7EE98\">com.example.concurrent<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #F6F6F4\">, <\/span><span style=\"color: #97E1F1\">attributes<\/span><span style=\"color: #F6F6F4\">: .concurrent)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F286C4\">var<\/span><span style=\"color: #F6F6F4\"> storage: &#091;<\/span><span style=\"color: #97E1F1; font-style: italic\">Int<\/span><span style=\"color: #F6F6F4\">&#093; <\/span><span style=\"color: #F286C4\">=<\/span><span style=\"color: #F6F6F4\"> []<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">queue.<\/span><span style=\"color: #97E1F1\">async<\/span><span style=\"color: #F6F6F4\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">    storage.<\/span><span style=\"color: #97E1F1\">append<\/span><span style=\"color: #F6F6F4\">(<\/span><span style=\"color: #BF9EEE\">1<\/span><span style=\"color: #F6F6F4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">queue.<\/span><span style=\"color: #97E1F1\">async<\/span><span style=\"color: #F6F6F4\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">    storage.<\/span><span style=\"color: #97E1F1\">append<\/span><span style=\"color: #F6F6F4\">(<\/span><span style=\"color: #BF9EEE\">2<\/span><span style=\"color: #F6F6F4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">queue.<\/span><span style=\"color: #97E1F1\">async<\/span><span style=\"color: #F6F6F4\">(<\/span><span style=\"color: #97E1F1\">flags<\/span><span style=\"color: #F6F6F4\">: .barrier) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">    storage.<\/span><span style=\"color: #97E1F1\">removeAll<\/span><span style=\"color: #F6F6F4\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">}<\/span><\/span>\n<span class=\"line\"><\/span><\/code><\/pre><\/div>\n\n\n\n<p>All tasks submitted before the barrier complete first. The barrier block then runs exclusively. Tasks submitted after the barrier wait until it finishes.<\/p>\n\n\n\n<p>This pattern works well for read-heavy scenarios with occasional writes. Regular tasks can run in parallel, while mutations are protected by barriers without switching to a fully serial queue.<\/p>\n\n\n\n<p>These primitives define how work is coordinated at the queue level. They operate independently from threads and remain separate from actor executors, which focus on isolation rather than scheduling policies.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Why a queue is not a thread<\/h2>\n\n\n\n<p>It is tempting to think about a queue as \u201ca thread with extra features\u201d. That mental shortcut causes subtle bugs.<\/p>\n\n\n\n<p>A queue:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>schedules work<\/li>\n\n\n\n<li>defines execution order<\/li>\n\n\n\n<li>may use many threads over time<\/li>\n<\/ul>\n\n\n\n<p>A thread:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>executes instructions<\/li>\n\n\n\n<li>has a lifetime controlled by the system<\/li>\n<\/ul>\n\n\n\n<p>The same queue may execute tasks on different threads at different moments. The same thread may execute work from different queues. The main queue is a special case, as it is bound to the main thread.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Actors and isolation<\/h2>\n\n\n\n<p>Swift Concurrency introduces actors to manage shared mutable state. An actor guarantees that only one piece of actor-isolated code runs at a time.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" style=\"color:#f6f6f4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>actor Counter {\n    private var value = 0\n\n    func increment() {\n        value += 1\n    }\n\n    func currentValue() -> Int {\n        value\n    }\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki dracula-soft\" style=\"background-color: #282A36\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #F286C4\">actor<\/span><span style=\"color: #F6F6F4\"> <\/span><span style=\"color: #97E1F1; font-style: italic\">Counter<\/span><span style=\"color: #F6F6F4\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">    <\/span><span style=\"color: #F286C4\">private<\/span><span style=\"color: #F6F6F4\"> <\/span><span style=\"color: #F286C4\">var<\/span><span style=\"color: #F6F6F4\"> value <\/span><span style=\"color: #F286C4\">=<\/span><span style=\"color: #F6F6F4\"> <\/span><span style=\"color: #BF9EEE\">0<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">    <\/span><span style=\"color: #F286C4\">func<\/span><span style=\"color: #F6F6F4\"> <\/span><span style=\"color: #62E884\">increment<\/span><span style=\"color: #F6F6F4\">() {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">        value <\/span><span style=\"color: #F286C4\">+=<\/span><span style=\"color: #F6F6F4\"> <\/span><span style=\"color: #BF9EEE\">1<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">    }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">    <\/span><span style=\"color: #F286C4\">func<\/span><span style=\"color: #F6F6F4\"> <\/span><span style=\"color: #62E884\">currentValue<\/span><span style=\"color: #F6F6F4\">() <\/span><span style=\"color: #F286C4\">-&gt;<\/span><span style=\"color: #F6F6F4\"> <\/span><span style=\"color: #97E1F1; font-style: italic\">Int<\/span><span style=\"color: #F6F6F4\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">        value<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>This looks similar to a serial queue at first glance. Both provide serialized access. The similarity ends once suspension enters the picture.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What an actor executor does<\/h2>\n\n\n\n<p>Every actor has an executor. The executor decides how to run jobs associated with that actor.<\/p>\n\n\n\n<p>You can think of it as a scheduler dedicated to preserving actor isolation. It receives units of work and ensures they execute according to the actor\u2019s rules.<\/p>\n\n\n\n<p>The default executor for most actors relies on the <a href=\"https:\/\/livsycode.com\/tag\/concurrency\/\" target=\"_blank\" rel=\"noopener\" title=\"\">Swift Concurrency<\/a> runtime and a shared thread pool. It does not bind the actor to a specific thread.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Why \u201cactor equals serial queue\u201d breaks down<\/h2>\n\n\n\n<p>The comparison helps at a very early stage, but it hides important details.<\/p>\n\n\n\n<p>Actors allow suspension:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" style=\"color:#f6f6f4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>actor ImageLoader {\n    func load(from url: URL) async throws -> Data {\n        let (data, _) = try await URLSession.shared.data(from: url)\n        return data\n    }\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki dracula-soft\" style=\"background-color: #282A36\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #F286C4\">actor<\/span><span style=\"color: #F6F6F4\"> <\/span><span style=\"color: #97E1F1; font-style: italic\">ImageLoader<\/span><span style=\"color: #F6F6F4\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">    <\/span><span style=\"color: #F286C4\">func<\/span><span style=\"color: #F6F6F4\"> <\/span><span style=\"color: #62E884\">load<\/span><span style=\"color: #F6F6F4\">(<\/span><span style=\"color: #62E884\">from<\/span><span style=\"color: #F6F6F4\"> <\/span><span style=\"color: #FFB86C; font-style: italic\">url<\/span><span style=\"color: #F6F6F4\">: URL) <\/span><span style=\"color: #F286C4\">async<\/span><span style=\"color: #F6F6F4\"> <\/span><span style=\"color: #F286C4\">throws<\/span><span style=\"color: #F6F6F4\"> <\/span><span style=\"color: #F286C4\">-&gt;<\/span><span style=\"color: #F6F6F4\"> Data {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">        <\/span><span style=\"color: #F286C4\">let<\/span><span style=\"color: #F6F6F4\"> (data, <\/span><span style=\"color: #BF9EEE\">_<\/span><span style=\"color: #F6F6F4\">) <\/span><span style=\"color: #F286C4\">=<\/span><span style=\"color: #F6F6F4\"> <\/span><span style=\"color: #F286C4\">try<\/span><span style=\"color: #F6F6F4\"> <\/span><span style=\"color: #F286C4\">await<\/span><span style=\"color: #F6F6F4\"> URLSession.shared.<\/span><span style=\"color: #97E1F1\">data<\/span><span style=\"color: #F6F6F4\">(<\/span><span style=\"color: #97E1F1\">from<\/span><span style=\"color: #F6F6F4\">: url)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">        <\/span><span style=\"color: #F286C4\">return<\/span><span style=\"color: #F6F6F4\"> data<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>When execution reaches <code>await<\/code>, the task suspends. The thread becomes free to execute other work. Later, the continuation resumes through the actor\u2019s executor.<\/p>\n\n\n\n<p>A serial queue does not behave this way. A synchronous block on a queue occupies a thread for its entire duration.<\/p>\n\n\n\n<p>This difference changes how you reason about performance and deadlocks. Actor-based code tends to avoid thread blocking and scales better under load.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Actor isolation and threads<\/h2>\n\n\n\n<p>Actor isolation does not imply a single thread.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" style=\"color:#f6f6f4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>actor Logger {\n    func log(_ message: String) {\n        print(Thread.current)\n    }\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki dracula-soft\" style=\"background-color: #282A36\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #F286C4\">actor<\/span><span style=\"color: #F6F6F4\"> <\/span><span style=\"color: #97E1F1; font-style: italic\">Logger<\/span><span style=\"color: #F6F6F4\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">    <\/span><span style=\"color: #F286C4\">func<\/span><span style=\"color: #F6F6F4\"> <\/span><span style=\"color: #62E884\">log<\/span><span style=\"color: #F6F6F4\">(<\/span><span style=\"color: #62E884\">_<\/span><span style=\"color: #F6F6F4\"> <\/span><span style=\"color: #FFB86C; font-style: italic\">message<\/span><span style=\"color: #F6F6F4\">: <\/span><span style=\"color: #97E1F1; font-style: italic\">String<\/span><span style=\"color: #F6F6F4\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">        <\/span><span style=\"color: #97E1F1\">print<\/span><span style=\"color: #F6F6F4\">(Thread.current)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>Multiple calls to <code>log<\/code> may run on different threads. The executor ensures that only one call accesses the actor\u2019s state at a time. The thread itself can vary between executions.<\/p>\n\n\n\n<p>The only widely used exception is <code>MainActor<\/code>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">MainActor and the main thread<\/h2>\n\n\n\n<p><code>MainActor<\/code> is a global actor tied to the main thread. Code annotated with <code>@MainActor<\/code> runs on the main dispatch queue.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" style=\"color:#f6f6f4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>@MainActor\nfinal class ViewModel {\n    var title: String = \"\"\n\n    func update() {\n        title = \"Updated\"\n    }\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki dracula-soft\" style=\"background-color: #282A36\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #F286C4\">@MainActor<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F286C4\">final<\/span><span style=\"color: #F6F6F4\"> <\/span><span style=\"color: #F286C4\">class<\/span><span style=\"color: #F6F6F4\"> <\/span><span style=\"color: #97E1F1\">ViewModel<\/span><span style=\"color: #F6F6F4\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">    <\/span><span style=\"color: #F286C4\">var<\/span><span style=\"color: #F6F6F4\"> title: <\/span><span style=\"color: #97E1F1; font-style: italic\">String<\/span><span style=\"color: #F6F6F4\"> <\/span><span style=\"color: #F286C4\">=<\/span><span style=\"color: #F6F6F4\"> <\/span><span style=\"color: #DEE492\">&quot;&quot;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">    <\/span><span style=\"color: #F286C4\">func<\/span><span style=\"color: #F6F6F4\"> <\/span><span style=\"color: #62E884\">update<\/span><span style=\"color: #F6F6F4\">() {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">        title <\/span><span style=\"color: #F286C4\">=<\/span><span style=\"color: #F6F6F4\"> <\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #E7EE98\">Updated<\/span><span style=\"color: #DEE492\">&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>This provides a safe bridge between Swift Concurrency and UIKit or SwiftUI, where UI updates must happen on the main thread.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Actor reentrancy and suspension points<\/h2>\n\n\n\n<p>Actor isolation guarantees that only one piece of actor-isolated code runs at a time. That guarantee applies to uninterrupted execution segments. Once a function reaches an <code>await<\/code>, the current task suspends and the actor becomes available for other work.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" style=\"color:#f6f6f4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>actor BankAccount {\n    private var balance: Int = 100\n\n    func withdraw(_ amount: Int) async {\n        guard balance >= amount else { return }\n\n        try? await Task.sleep(nanoseconds: 1_000_000_000)\n\n        balance -= amount\n    }\n\n    func deposit(_ amount: Int) {\n        balance += amount\n    }\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki dracula-soft\" style=\"background-color: #282A36\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #F286C4\">actor<\/span><span style=\"color: #F6F6F4\"> <\/span><span style=\"color: #97E1F1; font-style: italic\">BankAccount<\/span><span style=\"color: #F6F6F4\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">    <\/span><span style=\"color: #F286C4\">private<\/span><span style=\"color: #F6F6F4\"> <\/span><span style=\"color: #F286C4\">var<\/span><span style=\"color: #F6F6F4\"> balance: <\/span><span style=\"color: #97E1F1; font-style: italic\">Int<\/span><span style=\"color: #F6F6F4\"> <\/span><span style=\"color: #F286C4\">=<\/span><span style=\"color: #F6F6F4\"> <\/span><span style=\"color: #BF9EEE\">100<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">    <\/span><span style=\"color: #F286C4\">func<\/span><span style=\"color: #F6F6F4\"> <\/span><span style=\"color: #62E884\">withdraw<\/span><span style=\"color: #F6F6F4\">(<\/span><span style=\"color: #62E884\">_<\/span><span style=\"color: #F6F6F4\"> <\/span><span style=\"color: #FFB86C; font-style: italic\">amount<\/span><span style=\"color: #F6F6F4\">: <\/span><span style=\"color: #97E1F1; font-style: italic\">Int<\/span><span style=\"color: #F6F6F4\">) <\/span><span style=\"color: #F286C4\">async<\/span><span style=\"color: #F6F6F4\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">        <\/span><span style=\"color: #F286C4\">guard<\/span><span style=\"color: #F6F6F4\"> balance <\/span><span style=\"color: #F286C4\">&gt;=<\/span><span style=\"color: #F6F6F4\"> amount <\/span><span style=\"color: #F286C4\">else<\/span><span style=\"color: #F6F6F4\"> { <\/span><span style=\"color: #F286C4\">return<\/span><span style=\"color: #F6F6F4\"> }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">        <\/span><span style=\"color: #F286C4\">try?<\/span><span style=\"color: #F6F6F4\"> <\/span><span style=\"color: #F286C4\">await<\/span><span style=\"color: #F6F6F4\"> Task.<\/span><span style=\"color: #97E1F1\">sleep<\/span><span style=\"color: #F6F6F4\">(<\/span><span style=\"color: #97E1F1\">nanoseconds<\/span><span style=\"color: #F6F6F4\">: <\/span><span style=\"color: #BF9EEE\">1_000_000_000<\/span><span style=\"color: #F6F6F4\">)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">        balance <\/span><span style=\"color: #F286C4\">-=<\/span><span style=\"color: #F6F6F4\"> amount<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">    }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">    <\/span><span style=\"color: #F286C4\">func<\/span><span style=\"color: #F6F6F4\"> <\/span><span style=\"color: #62E884\">deposit<\/span><span style=\"color: #F6F6F4\">(<\/span><span style=\"color: #62E884\">_<\/span><span style=\"color: #F6F6F4\"> <\/span><span style=\"color: #FFB86C; font-style: italic\">amount<\/span><span style=\"color: #F6F6F4\">: <\/span><span style=\"color: #97E1F1; font-style: italic\">Int<\/span><span style=\"color: #F6F6F4\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">        balance <\/span><span style=\"color: #F286C4\">+=<\/span><span style=\"color: #F6F6F4\"> amount<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>The <code>withdraw<\/code> method checks the balance before suspension. While it is waiting, another call may update the same state. When execution resumes, the original assumption may no longer hold.<\/p>\n\n\n\n<p>This behavior is known as <a href=\"https:\/\/livsycode.com\/swift\/actor-reentrancy\/\" target=\"_blank\" rel=\"noopener\" title=\"\">reentrancy<\/a>. It requires treating any code after an <code>await<\/code> as operating on potentially changed state.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Custom executors and queues<\/h2>\n\n\n\n<p>Swift allows custom executors. In advanced scenarios, an actor can use a custom <code>SerialExecutor<\/code>, potentially backed by a dispatch queue.<\/p>\n\n\n\n<p>That does not make actors equivalent to queues. It shows that queues can be one possible implementation detail of an executor.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What happens at await<\/h2>\n\n\n\n<p>The interaction between threads and executors becomes clearer around suspension points.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" style=\"color:#f6f6f4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>actor DataStore {\n    func fetch() async -> String {\n        print(\"Before:\", Thread.current)\n\n        try? await Task.sleep(nanoseconds: 500_000_000)\n\n        print(\"After:\", Thread.current)\n        return \"Done\"\n    }\n}<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki dracula-soft\" style=\"background-color: #282A36\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #F286C4\">actor<\/span><span style=\"color: #F6F6F4\"> <\/span><span style=\"color: #97E1F1; font-style: italic\">DataStore<\/span><span style=\"color: #F6F6F4\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">    <\/span><span style=\"color: #F286C4\">func<\/span><span style=\"color: #F6F6F4\"> <\/span><span style=\"color: #62E884\">fetch<\/span><span style=\"color: #F6F6F4\">() <\/span><span style=\"color: #F286C4\">async<\/span><span style=\"color: #F6F6F4\"> <\/span><span style=\"color: #F286C4\">-&gt;<\/span><span style=\"color: #F6F6F4\"> <\/span><span style=\"color: #97E1F1; font-style: italic\">String<\/span><span style=\"color: #F6F6F4\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">        <\/span><span style=\"color: #97E1F1\">print<\/span><span style=\"color: #F6F6F4\">(<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #E7EE98\">Before:<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #F6F6F4\">, Thread.current)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">        <\/span><span style=\"color: #F286C4\">try?<\/span><span style=\"color: #F6F6F4\"> <\/span><span style=\"color: #F286C4\">await<\/span><span style=\"color: #F6F6F4\"> Task.<\/span><span style=\"color: #97E1F1\">sleep<\/span><span style=\"color: #F6F6F4\">(<\/span><span style=\"color: #97E1F1\">nanoseconds<\/span><span style=\"color: #F6F6F4\">: <\/span><span style=\"color: #BF9EEE\">500_000_000<\/span><span style=\"color: #F6F6F4\">)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">        <\/span><span style=\"color: #97E1F1\">print<\/span><span style=\"color: #F6F6F4\">(<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #E7EE98\">After:<\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #F6F6F4\">, Thread.current)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">        <\/span><span style=\"color: #F286C4\">return<\/span><span style=\"color: #F6F6F4\"> <\/span><span style=\"color: #DEE492\">&quot;<\/span><span style=\"color: #E7EE98\">Done<\/span><span style=\"color: #DEE492\">&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #F6F6F4\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>Before <code>await<\/code>, the code runs on some thread. At suspension, the thread is released. After resumption, execution continues through the actor\u2019s executor, potentially on another thread.<\/p>\n\n\n\n<p>The actor still guarantees correct isolation. The thread is free to change.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">A concise explanation that works well<\/h2>\n\n\n\n<p>A clear explanation usually separates responsibilities.<\/p>\n\n\n\n<p>A thread is an execution resource managed by the system. A dispatch queue schedules work and controls ordering. An actor executor runs actor-isolated jobs and enforces isolation rules within Swift Concurrency.<\/p>\n\n\n\n<p>Queues may use threads. Executors may use queues. These relationships exist without collapsing the concepts into one.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p>Once the roles are separated, the model becomes easier to apply in real code. Bugs related to race conditions, unexpected thread hops, or blocked execution tend to come from mixing these abstractions.<\/p>\n\n\n\n<p>Keeping a clean mental boundary between execution, scheduling, and isolation helps reason about both legacy GCD code and modern Swift Concurrency.<\/p>\n\n\n\n<div class=\"wp-block-group is-layout-constrained wp-block-group-is-layout-constrained\">\n<ul class=\"wp-block-social-links has-normal-icon-size has-icon-color has-icon-background-color is-style-default is-horizontal is-content-justification-left is-layout-flex wp-container-core-social-links-is-layout-f551e5d0 wp-block-social-links-is-layout-flex\" style=\"margin-right:0;margin-left:0\"><li style=\"color:#ffffff;background-color:#7a81ff;\" class=\"wp-social-link wp-social-link-linkedin has-white-color wp-block-social-link\"><a rel=\"noopener nofollow\" target=\"_blank\" href=\"https:\/\/www.linkedin.com\/in\/artem-mirzabekian\/\" class=\"wp-block-social-link-anchor\"><svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" version=\"1.1\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z\"><\/path><\/svg><span class=\"wp-block-social-link-label screen-reader-text\">LinkedIn<\/span><\/a><\/li>\n\n<li style=\"color:#ffffff;background-color:#7a81ff;\" class=\"wp-social-link wp-social-link-github has-white-color wp-block-social-link\"><a rel=\"noopener nofollow\" target=\"_blank\" href=\"https:\/\/github.com\/Livsy90\" class=\"wp-block-social-link-anchor\"><svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" version=\"1.1\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z\"><\/path><\/svg><span class=\"wp-block-social-link-label screen-reader-text\">GitHub<\/span><\/a><\/li><\/ul>\n\n\n<div class=\"rpbt_shortcode\">\n<h3>It might be interesting:<\/h3>\n<ul>\n\t\t\t\t\t\n\t\t\t<li>\n\t\t\t\t<a href=\"https:\/\/livsycode.com\/swift\/rebuilding-higher-order-functions-in-swift\/\">Rebuilding higher-order functions in Swift<\/a>\n\t\t\t<\/li>\n\t\t\t\t\t\n\t\t\t<li>\n\t\t\t\t<a href=\"https:\/\/livsycode.com\/swift\/stack-vs-heap-in-swift-interview-essentials\/\">Stack vs Heap in Swift<\/a>\n\t\t\t<\/li>\n\t\t\t\t\t\n\t\t\t<li>\n\t\t\t\t<a href=\"https:\/\/livsycode.com\/swift\/swift-arc-interview-essentials\/\">Swift ARC: Interview Essentials<\/a>\n\t\t\t<\/li>\n\t\t\t\t\t\n\t\t\t<li>\n\t\t\t\t<a href=\"https:\/\/livsycode.com\/swift\/xctest-in-ios-interview-essentials\/\">XCTest in iOS<\/a>\n\t\t\t<\/li>\n\t\t\t\t\t\n\t\t\t<li>\n\t\t\t\t<a href=\"https:\/\/livsycode.com\/uikit\/ios-app-launch-process-from-tap-to-first-frame\/\">iOS app launch process: from tap to first frame<\/a>\n\t\t\t<\/li>\n\t\t\t<\/ul>\n<\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Greetings, traveler! Questions around concurrency often drift into terminology. Thread, queue, executor \u2014 the words sound related, and many explanations blur the boundaries between them. That usually works until the first real bug appears, and then the model falls apart. A more reliable way to approach this topic is to separate the concepts by responsibility. [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[117],"tags":[135],"class_list":["post-3789","post","type-post","status-publish","format-standard","hentry","category-swift","tag-interview-preparation"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/livsycode.com\/wp-json\/wp\/v2\/posts\/3789","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/livsycode.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/livsycode.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/livsycode.com\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/livsycode.com\/wp-json\/wp\/v2\/comments?post=3789"}],"version-history":[{"count":4,"href":"https:\/\/livsycode.com\/wp-json\/wp\/v2\/posts\/3789\/revisions"}],"predecessor-version":[{"id":3818,"href":"https:\/\/livsycode.com\/wp-json\/wp\/v2\/posts\/3789\/revisions\/3818"}],"wp:attachment":[{"href":"https:\/\/livsycode.com\/wp-json\/wp\/v2\/media?parent=3789"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/livsycode.com\/wp-json\/wp\/v2\/categories?post=3789"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/livsycode.com\/wp-json\/wp\/v2\/tags?post=3789"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}