diff --git a/C#进阶/C#进阶.sln b/C#进阶/C#进阶.sln
index 8605ea8..a5b1c35 100644
--- a/C#进阶/C#进阶.sln
+++ b/C#进阶/C#进阶.sln
@@ -73,6 +73,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lesson17_协变逆变", "Le
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lesson17_协变逆变练习", "Lesson17_协变逆变练习\Lesson17_协变逆变练习.csproj", "{DDF7EBE2-4B8E-4B48-97BC-06EB4E55796A}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lesson18_多线程", "Lesson18_多线程\Lesson18_多线程.csproj", "{90769697-6F30-4BB0-A74E-3C3A9BDD8669}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lesson18_多线程练习", "Lesson18_多线程练习\Lesson18_多线程练习.csproj", "{D98DCA4D-7F46-4376-9BBF-F1343D058FF3}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -219,6 +223,14 @@ Global
{DDF7EBE2-4B8E-4B48-97BC-06EB4E55796A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DDF7EBE2-4B8E-4B48-97BC-06EB4E55796A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DDF7EBE2-4B8E-4B48-97BC-06EB4E55796A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {90769697-6F30-4BB0-A74E-3C3A9BDD8669}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {90769697-6F30-4BB0-A74E-3C3A9BDD8669}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {90769697-6F30-4BB0-A74E-3C3A9BDD8669}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {90769697-6F30-4BB0-A74E-3C3A9BDD8669}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D98DCA4D-7F46-4376-9BBF-F1343D058FF3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D98DCA4D-7F46-4376-9BBF-F1343D058FF3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D98DCA4D-7F46-4376-9BBF-F1343D058FF3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D98DCA4D-7F46-4376-9BBF-F1343D058FF3}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/C#进阶/Lesson18_多线程/Lesson18_多线程.csproj b/C#进阶/Lesson18_多线程/Lesson18_多线程.csproj
new file mode 100644
index 0000000..2150e37
--- /dev/null
+++ b/C#进阶/Lesson18_多线程/Lesson18_多线程.csproj
@@ -0,0 +1,10 @@
+
+
+
+ Exe
+ net8.0
+ enable
+ enable
+
+
+
diff --git a/C#进阶/Lesson18_多线程/Program.cs b/C#进阶/Lesson18_多线程/Program.cs
new file mode 100644
index 0000000..3991bf2
--- /dev/null
+++ b/C#进阶/Lesson18_多线程/Program.cs
@@ -0,0 +1,125 @@
+namespace Lesson18_多线程
+{
+ internal class Program
+ {
+ static bool isRunning = true;
+ static object obj = new object();
+ static void Main(string[] args)
+ {
+ #region 知识点一 了解线程前先了解进程
+ // 进程(Process)是计算机中的程序关于某数据集合上的一次运行活动
+ // 是系统进行资源分配和调度的基本单位,是操作系统结构的基础
+ // 说人话:打开一个应用程序就是在操作系统上开启了一个进程
+ // 进程之间可以相互独立运行,互不干扰
+ // 进程之间也可以相互访问、操作
+ #endregion
+
+ #region 知识点二 什么是线程
+ // 操作系统能够进行运算调度的最小单位。
+ // 它被包含在进程之中,是进程中的实际运作单位
+ // 一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程
+ // 我们目前写的程序 都在主线程中
+
+ // 简单理解线程:
+ // 就是代码从上到下运行的一条 “管道”
+ #endregion
+
+ #region 知识点三 什么是多线程
+ //我们可以通过代码 开启新的线程
+ //可以同时运行代码的多条“管道”
+ #endregion
+
+ #region 知识点四 语法相关
+ //线程类 Thread
+ //命名空间 System.Threading
+ //1.声明一个新的线程
+ // 注意 线程执行的代码 需要封装到一个函数中
+ // 新线程 将要执行的代码逻辑 被封装到了一个函数语句中
+ Thread t = new Thread(NewThreadLogic);
+
+ //2.启动线程
+ //默认为前台线程,不受主线程影响,会一直运行
+ t.Start();
+
+ //3.设置为后台线程
+ //后台线程 会随着主线程的结束而结束
+ t.IsBackground = true;
+
+ //4.关闭释放一个线程
+ //如果开启的线程不是死循环,是能够结束的,那么不用刻意去关闭,它会自动释放
+ //如果是死循环线程,那么有两种方式可以关闭
+ //4.1-死循环中设置一个开关变量 来控制循环结束
+
+ //Console.ReadKey();//卡一下t线程,让其保持运行
+ //isRunning = false;//按下后结束t线程
+
+ Console.ReadKey();//卡一下主线程,按下后结束
+
+ ////4.2-通过线程提供的方法(注意在.NET Core及以后的版本中 不推荐使用该方法)
+ ////终止线程 不推荐使用该方法 可能会引发不可预知的问题
+ //try
+ //{
+ // t.Abort();
+ // t = null;
+ //}
+ //catch
+ //{
+ // Console.WriteLine("ERROR");
+ //}
+ //t = null;
+
+ //5.线程休眠
+ //Thread.Sleep(1000);//让线程休眠一定时间,单位是毫秒
+ //现在在主线程中休眠1秒钟
+
+
+ #endregion
+
+ #region 知识点五 线程之间共享数据
+ //多个线程使用的内存时共享的,都属于该应用程序的内存空间
+ //所以要注意 当多线程 同时操作同一片内存区域时 可能会引发数据冲突问题
+ //可以通过加锁的形式避免问题
+
+ //lock
+ //当我们在做个线程中想要访问同样的类型数据时,可以使用lock关键字来锁定该数据
+ //这样当一个线程在访问该数据时,其他线程就无法访问该数据,直到该线程访问完毕,释放锁
+ //lock(引用类型的对象)
+
+
+ while (true)
+ {
+ lock(obj)
+ {
+ Console.SetCursorPosition(0, 0);
+ Console.ForegroundColor = ConsoleColor.Red;
+ Console.Write("????????????");
+ }
+ }
+ //注意:锁定的对象不能是值类型,必须是引用类型
+ //而且锁也会影响性能,所以只锁定必要的代码段
+
+ #endregion
+
+ #region 知识点六 多线程对于我们的意义
+ //可以用多线程专门处理一些复杂耗时的逻辑
+ //比如 寻路、网络通信等等
+ #endregion
+ }
+
+ static void NewThreadLogic()
+ {
+
+ while (isRunning)
+ {
+ //Thread.Sleep(1000);
+ //Console.WriteLine("NewThreadLogic");
+ lock (obj)
+ {
+ Console.SetCursorPosition(10, 5);
+ Console.ForegroundColor = ConsoleColor.Yellow;
+ Console.WriteLine("※");
+ }
+ }
+ }
+ }
+}
diff --git a/C#进阶/Lesson18_多线程练习/Lesson18_多线程练习.csproj b/C#进阶/Lesson18_多线程练习/Lesson18_多线程练习.csproj
new file mode 100644
index 0000000..2150e37
--- /dev/null
+++ b/C#进阶/Lesson18_多线程练习/Lesson18_多线程练习.csproj
@@ -0,0 +1,10 @@
+
+
+
+ Exe
+ net8.0
+ enable
+ enable
+
+
+
diff --git a/C#进阶/Lesson18_多线程练习/Program.cs b/C#进阶/Lesson18_多线程练习/Program.cs
new file mode 100644
index 0000000..5b11fe1
--- /dev/null
+++ b/C#进阶/Lesson18_多线程练习/Program.cs
@@ -0,0 +1,107 @@
+namespace Lesson18_多线程练习
+{
+ enum E_Direction
+ {
+ Up,
+ Down,
+ Left,
+ Right
+ }
+ struct Position
+ {
+ public int X;
+ public int Y;
+ }
+ interface IDraw
+ {
+ public void Draw();
+ }
+ class Snake : IDraw
+ {
+ public E_Direction Direction;
+ Position Position;
+ public Snake()
+ {
+ Position.X = 15;
+ Position.Y = 5;
+ Direction = E_Direction.Right;
+ }
+
+ public void Move()
+ {
+ switch (this.Direction)
+ {
+ case E_Direction.Up:
+ Position.Y -= 1;
+ break;
+ case E_Direction.Down:
+ Position.Y += 1;
+ break;
+ case E_Direction.Left:
+ Position.X -= 2;
+ break;
+ case E_Direction.Right:
+ Position.X += 2;
+ break;
+ default:
+ break;
+ }
+ }
+ public void Draw()
+ {
+ Console.SetCursorPosition(Position.X, Position.Y);
+ Console.Write("■");
+ }
+ public void Clean()
+ {
+ Console.SetCursorPosition(Position.X, Position.Y);
+ Console.Write(" ");
+ }
+ public void ChangeDirection(E_Direction direction)
+ {
+ this.Direction = direction;
+ }
+ }
+ class Program
+ {
+ static Snake snake;
+ static void Main(string[] args)
+ {
+ snake = new Snake();
+ Console.CursorVisible = false;
+ Thread inputThread = new Thread(input);
+ inputThread.Start();
+ while (true)
+ {
+ Thread.Sleep(500);
+ snake.Clean();
+ snake.Move();
+ snake.Draw();
+ }
+
+ }
+ static void input()
+ {
+ while (true)
+ {
+ switch(Console.ReadKey(true).Key)
+ {
+ case ConsoleKey.UpArrow:
+ snake.ChangeDirection(E_Direction.Up);
+ break;
+ case ConsoleKey.DownArrow:
+ snake.ChangeDirection(E_Direction.Down);
+ break;
+ case ConsoleKey.LeftArrow:
+ snake.ChangeDirection(E_Direction.Left);
+ break;
+ case ConsoleKey.RightArrow:
+ snake.ChangeDirection(E_Direction.Right);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+}