Thread类的使用(.net)

1.作用:创建和控制线程,设置其优先级并获取其状态。

2.构造函数
Thread(ParameterizedThreadStart)        初始化 Thread 类的新实例,指定允许对象在线程启动时传递给线程的委托。
Thread(ParameterizedThreadStart,?Int32)    初始化 Thread 类的新实例,指定允许对象在线程启动时传递给线程的委托,并指定线程的最大堆栈大小。。
Thread(ThreadStart)                        初始化 Thread 类的新实例。
Thread(ThreadStart,?Int32)                初始化 Thread 类的新实例,指定线程的最大堆栈大小。

3.属性
ApartmentState        已过时。 获取或设置此线程的单元状态。
CurrentContext        获取线程正在其中执行的当前上下文。
CurrentCulture        获取或设置当前线程的区域性。
CurrentPrincipal    获取或设置线程的当前负责人(对基于角色的安全性而言)。
CurrentThread        获取当前正在运行的线程。
CurrentUICulture    获取或设置资源管理器使用的当前区域性以便在运行时查找区域性特定的资源。
ExecutionContext    获取 ExecutionContext 对象,该对象包含有关当前线程的各种上下文的信息。
IsAlive                获取指示当前线程的执行状态的值。
IsBackground        获取或设置一个值,该值指示某个线程是否为后台线程。
IsThreadPoolThread    获取指示线程是否属于托管线程池的值。
ManagedThreadId        获取当前托管线程的唯一标识符。
Name                获取或设置线程的名称。
Priority            获取或设置指示线程的调度优先级的值。
ThreadState            获取一个值,该值包含当前线程的状态。

4.方法
Abort()    在调用此方法的线程上引发 ThreadAbortException,以开始终止此线程的过程。 调用此方法通常会终止线程。
Abort(Object)    引发在其上调用的线程中的 ThreadAbortException 以开始处理终止线程,同时提供有关线程终止的异常信息。 调用此方法通常会终止线程。
AllocateDataSlot()    在所有线程上分配未命名的数据槽。 为了获得更好的性能,请改用以 ThreadStaticAttribute 特性标记的字段。
AllocateNamedDataSlot(String)    在所有线程上分配已命名的数据槽。 为了获得更好的性能,请改用以 ThreadStaticAttribute 特性标记的字段。
BeginCriticalRegion()通知宿主执行将要进入一个代码区域,在该代码区域内线程中止或未经处理异常的影响可能会危害应用程序域中的其他任务。
BeginThreadAffinity()    通知宿主托管代码将要执行依赖于当前物理操作系统线程的标识的指令。
DisableComObjectEagerCleanup()    对于当前线程关闭运行时可调用包装 (RCW) 的自动清理。
EndCriticalRegion()    通知宿主执行将要进入一个代码区域,在该代码区域内线程中止或未经处理异常的影响限于当前任务。
EndThreadAffinity()    通知宿主托管代码已执行完依赖于当前物理操作系统线程的标识的指令。
Equals(Object)确定指定的对象是否等于当前对象。(从 Object 继承。)
Finalize()    确保垃圾回收器回收 Thread 对象时释放资源并执行其他清理操作。(替代 CriticalFinalizerObject.Finalize()。)
FreeNamedDataSlot(String)    为进程中的所有线程消除名称与槽之间的关联。 为了获得更好的性能,请改用以 ThreadStaticAttribute 特性标记的字段。
GetApartmentState()    返回表示单元状态的 ApartmentState 值。
GetCompressedStack()    已过时。 返回 CompressedStack 对象,此对象可用于获取当前线程的堆栈。
GetData(LocalDataStoreSlot)    在当前线程的当前域中从当前线程上指定的槽中检索值。 为了获得更好的性能,请改用以 ThreadStaticAttribute 特性标记的字段。
GetDomain()    返回当前线程正在其中运行的当前域。
GetDomainID()    返回唯一的应用程序域标识符。
GetHashCode()    返回当前线程的哈希代码。(替代 Object.GetHashCode()。)
GetNamedDataSlot(String)    查找命名的数据槽。 为了获得更好的性能,请改用以 ThreadStaticAttribute 特性标记的字段。
GetType()    获取当前实例的 Type。(从 Object 继承。)
Interrupt()    中断处于 WaitSleepJoin 线程状态的线程。
Join()    阻止调用线程,直到此实例所表示的线程终止,同时继续执行标准的 COM 和 SendMessage 泵处理期间。
Join(Int32)    阻止调用线程,直到此实例所表示的线程终止或经过指定的时间,同时继续执行标准的 COM 和 sendmessage 消息泵处理。
Join(TimeSpan)    阻止调用线程,直到此实例所表示的线程终止或经过指定的时间,同时继续执行标准的 COM 和 sendmessage 消息泵处理。
MemoryBarrier()按如下方式同步内存访问:执行当前线程的处理器在对指令重新排序时,不能采用先执行MemoryBarrier调用之后的内存存取,再执行MemoryBarrier调用之前的内存存取的方式。
ResetAbort()    取消当前线程所请求的 Abort。
Resume()    已过时。 继续已挂起的线程。
SetApartmentState(ApartmentState)    在线程启动前设置其单元状态。
SetCompressedStack(CompressedStack)    已过时。 将捕获的 CompressedStack 应用到当前线程。
SetData(LocalDataStoreSlot,?Object)    在当前正在运行的线程上为此线程的当前域在指定槽中设置数据。 为了提高性能,请改用用 ThreadStaticAttribute 属性标记的字段。
Sleep(Int32)    将当前线程挂起指定的毫秒数。
Sleep(TimeSpan)    将当前线程挂起指定的时间。
SpinWait(Int32)    导致线程等待由 iterations 参数定义的时间量。
Start()    导致操作系统将当前实例的状态更改为 ThreadState.Running。
Start(Object)    导致操作系统将当前实例的状态更改为 ThreadState.Running,并选择提供包含线程执行的方法要使用的数据的对象。
Suspend()    已过时。 挂起线程,或者如果线程已挂起,则不起作用。
ToString()    返回表示当前对象的字符串。(从 Object 继承。)
TrySetApartmentState(ApartmentState)    在线程启动前设置其单元状态。
VolatileRead(Byte)    读取字段值。 无论处理器的数目或处理器缓存的状态如何,该值都是由计算机的任何处理器写入的最新值。
VolatileRead(Double)    读取字段值。 无论处理器的数目或处理器缓存的状态如何,该值都是由计算机的任何处理器写入的最新值。
VolatileRead(Int16)    读取字段值。 无论处理器的数目或处理器缓存的状态如何,该值都是由计算机的任何处理器写入的最新值。
VolatileRead(Int32)    读取字段值。 无论处理器的数目或处理器缓存的状态如何,该值都是由计算机的任何处理器写入的最新值。
VolatileRead(Int64)    读取字段值。 无论处理器的数目或处理器缓存的状态如何,该值都是由计算机的任何处理器写入的最新值。
VolatileRead(IntPtr)    读取字段值。 无论处理器的数目或处理器缓存的状态如何,该值都是由计算机的任何处理器写入的最新值。
VolatileRead(Object)    读取字段值。 无论处理器的数目或处理器缓存的状态如何,该值都是由计算机的任何处理器写入的最新值。
VolatileRead(SByte)    读取字段值。 无论处理器的数目或处理器缓存的状态如何,该值都是由计算机的任何处理器写入的最新值。
VolatileRead(Single)    读取字段值。 无论处理器的数目或处理器缓存的状态如何,该值都是由计算机的任何处理器写入的最新值。
VolatileRead(UInt16)    读取字段值。 无论处理器的数目或处理器缓存的状态如何,该值都是由计算机的任何处理器写入的最新值。
VolatileRead(UInt32)    读取字段值。 无论处理器的数目或处理器缓存的状态如何,该值都是由计算机的任何处理器写入的最新值。
VolatileRead(UInt64)    读取字段值。 无论处理器的数目或处理器缓存的状态如何,该值都是由计算机的任何处理器写入的最新值。
VolatileRead(UIntPtr)    读取字段值。 无论处理器的数目或处理器缓存的状态如何,该值都是由计算机的任何处理器写入的最新值。
VolatileWrite(Byte,?Byte)    立即向字段写入一个值,以使该值对计算机中的所有处理器都可见。
VolatileWrite(Double,?Double)    立即向字段写入一个值,以使该值对计算机中的所有处理器都可见。
VolatileWrite(Int16,?Int16)    立即向字段写入一个值,以使该值对计算机中的所有处理器都可见。
VolatileWrite(Int32,?Int32)    立即向字段写入一个值,以使该值对计算机中的所有处理器都可见。
VolatileWrite(Int64,?Int64)    立即向字段写入一个值,以使该值对计算机中的所有处理器都可见。
VolatileWrite(IntPtr,?IntPtr)    立即向字段写入一个值,以使该值对计算机中的所有处理器都可见。
VolatileWrite(Object,?Object)    立即向字段写入一个值,以使该值对计算机中的所有处理器都可见。
VolatileWrite(SByte,?SByte)    立即向字段写入一个值,以使该值对计算机中的所有处理器都可见。
VolatileWrite(Single,?Single)    立即向字段写入一个值,以使该值对计算机中的所有处理器都可见。
VolatileWrite(UInt16,?UInt16)    立即向字段写入一个值,以使该值对计算机中的所有处理器都可见。
VolatileWrite(UInt32,?UInt32)    立即向字段写入一个值,以使该值对计算机中的所有处理器都可见。
VolatileWrite(UInt64,?UInt64)    立即向字段写入一个值,以使该值对计算机中的所有处理器都可见。
VolatileWrite(UIntPtr,?UIntPtr)    立即向字段写入一个值,以使该值对计算机中的所有处理器都可见。
Yield()    导致调用线程执行准备好在当前处理器上运行的另一个线程。 由操作系统选择要执行的线程。

5.启动线程
通过提供一个委托,表示该线程是在其类构造函数中执行的方法来启动一个线程。 然后,可以调用 Start 方法开始执行。
Thread 构造函数可以采用两个委托类型,具体取决于是否可以将参数传递给要执行的方法之一︰
如果该方法不具有任何参数,则传递 ThreadStart 委托给的构造函数。 它具有签名︰

public delegate void ThreadStart()

下面的示例创建并启动执行的线程 ExecuteInForeground 方法。 该方法显示一些线程属性,有关的信息,然后执行的循环它半秒暂停并显示已用的秒数。 线程执行时至少五秒内,则循环结束,并且该线程将终止执行。

using System;
using System.Diagnostics;
using System.Threading;

public class Example
{
   public static void Main()
   {
      var th = new Thread(ExecuteInForeground);
      th.Start();
      Thread.Sleep(1000);
      Console.WriteLine("Main thread ({0}) exiting...",
                        Thread.CurrentThread.ManagedThreadId);
   }

   private static void ExecuteInForeground()
   {
      DateTime start = DateTime.Now;
      var sw = Stopwatch.StartNew();
      Console.WriteLine("Thread {0}: {1}, Priority {2}",
                        Thread.CurrentThread.ManagedThreadId,
                        Thread.CurrentThread.ThreadState,
                        Thread.CurrentThread.Priority);
      do {
         Console.WriteLine("Thread {0}: Elapsed {1:N2} seconds",
                           Thread.CurrentThread.ManagedThreadId,
                           sw.ElapsedMilliseconds / 1000.0);
         Thread.Sleep(500);
      } while (sw.ElapsedMilliseconds <= 5000);
      sw.Stop();
   }
}

// The example displays output like the following:
//       Thread 3: Running, Priority Normal
//       Thread 3: Elapsed 0.00 seconds
//       Thread 3: Elapsed 0.51 seconds
//       Main thread (1) exiting...
//       Thread 3: Elapsed 1.02 seconds
//       Thread 3: Elapsed 1.53 seconds
//       Thread 3: Elapsed 2.05 seconds
//       Thread 3: Elapsed 2.55 seconds
//       Thread 3: Elapsed 3.07 seconds
//       Thread 3: Elapsed 3.57 seconds
//       Thread 3: Elapsed 4.07 seconds
//       Thread 3: Elapsed 4.58 seconds


如果该方法具有参数,则传递 ParameterizedThreadStart 委托给的构造函数。 它具有签名︰
public delegate void ParameterizedThreadStart(object obj)
然后,执行该委托的方法可以强制转换 (在 C#) 或者 (在 Visual Basic 中) 将参数转换为适当的类型。
下面的示例是等同于前面的代码,只不过它将调用 Thread(ParameterizedThreadStart) 构造函数。 此版本的 ExecuteInForeground 方法只有一个参数表示的近似毫秒所要执行的循环数。

using System;
using System.Diagnostics;
using System.Threading;

public class Example
{
   public static void Main()
   {
      var th = new Thread(ExecuteInForeground);
      th.Start(4500);
      Thread.Sleep(1000);
      Console.WriteLine("Main thread ({0}) exiting...",
                        Thread.CurrentThread.ManagedThreadId);
   }

   private static void ExecuteInForeground(Object obj)
   {
      int interval;
      try {
         interval = (int) obj;
      }
      catch (InvalidCastException) {
         interval = 5000;
      }
      DateTime start = DateTime.Now;
      var sw = Stopwatch.StartNew();
      Console.WriteLine("Thread {0}: {1}, Priority {2}",
                        Thread.CurrentThread.ManagedThreadId,
                        Thread.CurrentThread.ThreadState,
                        Thread.CurrentThread.Priority);
      do {
         Console.WriteLine("Thread {0}: Elapsed {1:N2} seconds",
                           Thread.CurrentThread.ManagedThreadId,
                           sw.ElapsedMilliseconds / 1000.0);
         Thread.Sleep(500);
      } while (sw.ElapsedMilliseconds <= interval);
      sw.Stop();
   }
}

// The example displays output like the following:
//       Thread 3: Running, Priority Normal
//       Thread 3: Elapsed 0.00 seconds
//       Thread 3: Elapsed 0.52 seconds
//       Main thread (1) exiting...
//       Thread 3: Elapsed 1.03 seconds
//       Thread 3: Elapsed 1.55 seconds
//       Thread 3: Elapsed 2.06 seconds
//       Thread 3: Elapsed 2.58 seconds
//       Thread 3: Elapsed 3.09 seconds
//       Thread 3: Elapsed 3.61 seconds
//       Thread 3: Elapsed 4.12 seconds


不需要保留对引用 Thread 对象后启动线程。 线程将继续执行,直到线程过程已完成。
线程对象的检索问题
您可以使用静态 (Shared 在 Visual Basic 中) CurrentThread 属性来检索对当前执行线程的线程正在执行的代码中的引用。 下面的示例使用 CurrentThread 属性来显示有关主应用程序线程、 另一个前台线程、 后台线程和一个线程池线程的信息。

using System;
using System.Threading;

public class Example
{
   static Object obj = new Object();

   public static void Main()
   {
      ThreadPool.QueueUserWorkItem(ShowThreadInformation);
      var th1 = new Thread(ShowThreadInformation);
      th1.Start();
      var th2 = new Thread(ShowThreadInformation);
      th2.IsBackground = true;
      th2.Start();
      Thread.Sleep(500);
      ShowThreadInformation(null);
   }

   private static void ShowThreadInformation(Object state)
   {
      lock (obj) {
         var th  = Thread.CurrentThread;
         Console.WriteLine("Managed thread #{0}: ", th.ManagedThreadId);
         Console.WriteLine("   Background thread: {0}", th.IsBackground);
         Console.WriteLine("   Thread pool thread: {0}", th.IsThreadPoolThread);
         Console.WriteLine("   Priority: {0}", th.Priority);
         Console.WriteLine("   Culture: {0}", th.CurrentCulture.Name);
         Console.WriteLine("   UI culture: {0}", th.CurrentUICulture.Name);
         Console.WriteLine();
      }   
   }
}


// The example displays output like the following:
//       Managed thread #6:
//          Background thread: True
//          Thread pool thread: False
//          Priority: Normal
//          Culture: en-US
//          UI culture: en-US
//       
//       Managed thread #3:
//          Background thread: True
//          Thread pool thread: True
//          Priority: Normal
//          Culture: en-US
//          UI culture: en-US
//       
//       Managed thread #4:
//          Background thread: False
//          Thread pool thread: False
//          Priority: Normal
//          Culture: en-US
//          UI culture: en-US
//       
//       Managed thread #1:
//          Background thread: False
//          Thread pool thread: False
//          Priority: Normal
//          Culture: en-US
//          UI culture: en-US


前台和后台线程
实例 Thread 类表示前台线程或后台线程。 后台线程将与前台线程有一处例外︰ 如果所有前台线程已都终止,后台线程不会保留正运行的进程。 一旦所有前台线程已都停止,则运行时将停止所有后台线程,并关闭。
默认情况下,在前台执行下面的线程︰
主应用程序中的线程。
通过调用创建的所有线程 Thread 类构造函数。
默认情况下,在后台中执行以下的线程︰
线程池线程,它们是由运行时维护的工作线程池。 可以通过使用线程池线程上配置的线程池和计划工作 ThreadPool 类。
System_CAPS_note注意
在线程池线程上自动执行基于任务的异步操作。 基于任务的异步操作使用 Task 和 Task<TResult> 类以实现 基于任务的异步模式。
从非托管代码进入托管的执行环境的所有线程。
您可以更改一个线程以在后台执行通过设置 IsBackground 属性在任何时间。 后台线程可用于任何操作都应继续,只要应用程序正在运行,但不是应阻止应用程序终止,如监视文件系统更改,或者传入套接字连接。
下面的示例说明了前台和后台线程之间的差异。 就像在第一个示例 启动线程 部分,只不过它将设置要在后台执行然后再启动它的线程。 如输出所示,然后才能执行五秒内已中断循环。

using System;
using System.Diagnostics;
using System.Threading;

public class Example
{
   public static void Main()
   {
      var th = new Thread(ExecuteInForeground);
      th.IsBackground = true;
      th.Start();
      Thread.Sleep(1000);
      Console.WriteLine("Main thread ({0}) exiting...",
                        Thread.CurrentThread.ManagedThreadId);
   }

   private static void ExecuteInForeground()
   {
      DateTime start = DateTime.Now;
      var sw = Stopwatch.StartNew();
      Console.WriteLine("Thread {0}: {1}, Priority {2}",
                        Thread.CurrentThread.ManagedThreadId,
                        Thread.CurrentThread.ThreadState,
                        Thread.CurrentThread.Priority);
      do {
         Console.WriteLine("Thread {0}: Elapsed {1:N2} seconds",
                           Thread.CurrentThread.ManagedThreadId,
                           sw.ElapsedMilliseconds / 1000.0);
         Thread.Sleep(500);
      } while (sw.ElapsedMilliseconds <= 5000);
      sw.Stop();
   }
}

// The example displays output like the following:
//       Thread 3: Background, Priority Normal
//       Thread 3: Elapsed 0.00 seconds
//       Thread 3: Elapsed 0.51 seconds
//       Main thread (1) exiting...


区域性和线程
每个线程都有一个区域性,由表示 CurrentCulture 属性和 UI 区域性,由表示 CurrentUICulture 属性。 当前区域性支持分析和格式设置,字符串比较和排序,诸如区分区域性的操作,还可以控制书写系统和线程使用的日历。 当前 UI 区域性提供用于区分区域性检索资源文件中的资源。
实例化一个新线程时,其区域性和 UI 区域性定义的当前系统区域性和 UI 区域性,而不是区域性和 UI 区域性从中创建新线程的线程。 这意味着,例如,如果当前系统区域性为英语 (美国),主要应用程序线程的当前区域性为法语 (法国),通过调用创建一个新线程的区域性 Thread(ParameterizedThreadStart) 从主线程的构造函数是英语 (美国) 和不是法语 (法国)。 有关详细信息,请参阅的"区域性和线程"部分 CultureInfo 类主题。
System_CAPS_important重要事项
这不是执行该目标的应用程序的异步操作的线程,则返回 true .NET Framework 4.6 和更高版本中的,在这种情况下,区域性和 UI 区域性中是异步操作的上下文的一部分; 一个异步操作,默认情况下在其执行的线程继承区域性和 UI 区域性从中启动异步操作的线程。 有关详细信息,请参阅的"区域性和基于任务的异步操作"部分 CultureInfo 类主题。
您可以执行下列任一操作,确保所有线程执行应用程序中共享相同的区域性和 UI 区域性︰
您可以将传递 CultureInfo 对象,表示该区域性 ParameterizedThreadStart 委派或 ThreadPool.QueueUserWorkItem(WaitCallback,?Object) 方法。
在上运行的应用程序 .NET Framework 4.5 和更高版本,您可以定义区域性和 UI 区域性,则要分配给应用程序域中创建的值设置的所有线程 CultureInfo.DefaultThreadCurrentCulture 和 CultureInfo.DefaultThreadCurrentUICulture 属性。 请注意这是每个应用程序域的设置。
有关详细信息和示例,请参阅的"区域性和线程"部分 CultureInfo 类主题。
获取相关信息和控制线程
您可以检索多个提供有关线程的信息的属性值。 在某些情况下,您还可以设置这些属性值以控制该线程的操作。 这些线程属性包括︰
名称。 Name 为写入-一次可用于标识某个线程的属性。 其默认值是 null。
一个哈希代码,它可以通过调用检索 GetHashCode 方法。 可以使用的哈希代码来唯一地标识线程;您的线程的生存期内,其哈希代码不会与来自其他线程,而不考虑从中获取值的应用程序域的值。
线程 id。 只读的值 ManagedThreadId 属性由运行时分配,并唯一地标识在其进程内部的线程。
System_CAPS_note注意
操作系统 ThreadId 具有与托管线程没有固定的关系,因为非托管的宿主可以控制托管和非托管线程之间的关系。 具体而言,一个复杂的主机可以使用 CLR Hosting API 调度多个托管的线程针对同一操作系统线程,或者在不同的操作系统线程之间移动托管的线程。
线程的当前状态。 其存在状态的持续时间内,线程是始终在一个或多个状态定义 ThreadState 属性。
一个计划的优先级别由定义 ThreadPriority 属性。 虽然可以设置此值以请求线程的优先级,但不保证操作系统被接受。
只读 IsThreadPoolThread 属性,用于指示线程是否是一个线程池线程。
IsBackground 属性。 有关详细信息,请参阅 前台和后台线程 部分。
访问 Thread 类的源代码
若要查看的.NET Framework 源代码 Thread 类,请参阅 Reference Source。 您可以浏览源代码、 下载脱机查看参考资料和调试; 在逐句通过源 (包括修补程序和更新)see instructions.
示例
下面的示例演示了简单的线程处理功能。

using System;
using System.Threading;

// Simple threading scenario:  Start a static method running
// on a second thread.
public class ThreadExample {
    // The ThreadProc method is called when the thread starts.
    // It loops ten times, writing to the console and yielding
    // the rest of its time slice each time, and then ends.
    public static void ThreadProc() {
        for (int i = 0; i < 10; i++) {
            Console.WriteLine("ThreadProc: {0}", i);
            // Yield the rest of the time slice.
            Thread.Sleep(0);
        }
    }

    public static void Main() {
        Console.WriteLine("Main thread: Start a second thread.");
        // The constructor for the Thread class requires a ThreadStart
        // delegate that represents the method to be executed on the
        // thread.  C# simplifies the creation of this delegate.
        Thread t = new Thread(new ThreadStart(ThreadProc));

        // Start ThreadProc.  Note that on a uniprocessor, the new
        // thread does not get any processor time until the main thread
        // is preempted or yields.  Uncomment the Thread.Sleep that
        // follows t.Start() to see the difference.
        t.Start();
        //Thread.Sleep(0);

        for (int i = 0; i < 4; i++) {
            Console.WriteLine("Main thread: Do some work.");
            Thread.Sleep(0);
        }

        Console.WriteLine("Main thread: Call Join(), to wait until ThreadProc ends.");
        t.Join();
        Console.WriteLine("Main thread: ThreadProc.Join has returned.  Press Enter to end program.");
        Console.ReadLine();
    }
}

此代码生成类似于以下输出︰
[VB, C++, C#]
Main thread: Start a second thread.
Main thread: Do some work.
ThreadProc: 0
Main thread: Do some work.
ThreadProc: 1
Main thread: Do some work.
ThreadProc: 2
Main thread: Do some work.
ThreadProc: 3
Main thread: Call Join(), to wait until ThreadProc ends.
ThreadProc: 4
ThreadProc: 5
ThreadProc: 6
ThreadProc: 7
ThreadProc: 8
ThreadProc: 9
Main thread: ThreadProc.Join has returned.  Press Enter to end program.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值