程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 線程系列03,多線程共享數據,多線程不共享數據,03多線程

線程系列03,多線程共享數據,多線程不共享數據,03多線程

編輯:C#入門知識

線程系列03,多線程共享數據,多線程不共享數據,03多線程


多線程編程,有時希望每個線程的數據相互隔離互不影響,有時卻希望線程間能共享數據,並保持同步。本篇體驗多線程共享和不共享數據。


□ 多線程不共享數據

對於多線程,CLR到底是怎樣為它們分配內存棧空間呢?是"一個蘿卜一個坑",每個線程都有自己的棧空間;還是"大樹底下好乘涼",所有的線程共享同一個棧空間?

我們讓2個線程執行相同的靜態方法,用到相同的變量,通過打印變量來求證多線程棧空間的分配情況。

    class Program
    {
        static void Main(string[] args)
        {
            new Thread(SayHi).Start();
            SayHi();
        }
        static void SayHi()
        {
            for (int i = 0; i < 5; i++)
            {
                Console.WriteLine("我是線程#" + Thread.CurrentThread.ManagedThreadId + "這是我的第" +i+  "次說hello");
            }
        }
    }

雖然2個線程交叉執行,但都說了4次的hello。說明CLR為2個線程都分配了棧空間,變量i在各自的棧空間中相互不受影響。

 

□ 多線程共享數據

線程間是需要相互合作的,多個線程如何共享數據呢?

 

※ 共享實例變量

讓2個線程執行同一個實例方法,看看是否可以共享對象實例的公共字段。

using System;
using System.Threading;
namespace ConsoleApplication1
{
    class Program
    {
        public int whatever;
        static void Main(string[] args)
        {
            Program p = new Program();
            new Thread(p.PrintVariable).Start();
            p.PrintVariable();
        }
        void PrintVariable()
        {
            whatever++;
            Console.WriteLine("線程#" + Thread.CurrentThread.ManagedThreadId + " 執行後whatever變量為:" +whatever);
        }
    }
}

可見,2個線程共享了Program實例的公共字段。

 

另外,關於線程間共享數據,一個繞不開的話題是:如何避免數據不同步?使用lock語句塊可以解決這個問題,在同一時刻只允許有一個線程進入方法內部。這樣的做法也叫”線程安全”。

    class Program
    {
        public int whatever;
        //static readonly編譯期變量 在聲明時賦值
        static readonly object locker = new object();
        static void Main(string[] args)
        {
            Program p = new Program();
            new Thread(p.PrintVariable).Start();
            p.PrintVariable();
        }
        void PrintVariable()
        {
            lock (locker)
            {
                whatever++;
                Console.WriteLine("線程#" + Thread.CurrentThread.ManagedThreadId + " 執行後whatever變量為:" + whatever);
            }           
        }
    }

當一個線程在lock語句塊執行,另一個線程等待,等待的這個線程在那刻不消耗CPU。   

 

※ 共享靜態字段

    class Program
    {
        static int whatever;
        //static readonly編譯期變量 在聲明時賦值
        static readonly object locker = new object();
        static void Main(string[] args)
        {
            new Thread(PrintVariable).Start();
            PrintVariable();
        }
        static void PrintVariable()
        {
            lock (locker)
            {
                whatever++;
                Console.WriteLine("線程#" + Thread.CurrentThread.ManagedThreadId + " 執行後whatever變量為:" + whatever);
            }           
        }
    }

 

總結:
○ CLR會給每個線程分配內存棧空間,棧中的變量互不影響
○ 多線程可以共享對象實例的公共成員和類的靜態字段
○ 線程間共享數據需要考慮"線程安全",使用lock語句塊可保證"線程安全"

 

線程系列包括:

線程系列01,前台線程,後台線程,線程同步

線程系列02,多個線程同時處理一個耗時較長的任務以節省時間

線程系列03,多線程共享數據,多線程不共享數據


一個java數據多線程數據共享的例子,

public class ThreadPoolManager {
private static ThreadPoolManager instance = null;
private List<Upload> taskQueue = Collections.synchronizedList(new LinkedList<Upload>());//任務隊列
private WorkThread[] workQueue ; //工作線程(真正執行任務的線程)
private static int worker_num = 6; //工作線程數量(默認工作線程數量是6)
private static int worker_count = 0;

private ThreadPoolManager(){
this(6);
}
private ThreadPoolManager(int num){
worker_num = num;
workQueue = new WorkThread[worker_num];
for(int i=0;i<worker_num;i++){
workQueue[i] = new WorkThread(i);
}
}

public static synchronized ThreadPoolManager getInstance(){
if(instance==null)
instance = new ThreadPoolManager();
return instance;
}

public void addTask(Upload task){
//對任務隊列的操作要上鎖
synchronized (taskQueue) {
if(task!=null){
taskQueue.add(task);
taskQueue.notifyAll();
System.out.println("task id "+task.getInfo() + " submit!");
}

}
}

public void BatchAddTask(Upload[] tasks){
//對任務隊列的修改操作要上鎖
synchronized (taskQueue) {
for(Upload e:tasks){
if(e!=null){
taskQueue.add(e);
taskQueue.notifyAll();
System.out.println("t......余下全文>>
 

c# 多線程共享數據的問題

共享數據不難,只需要在創建線程對象的時候將你需要共享的數據對象在啟動線程前(通常是構造線程對象的時候)傳入即可。但是必須注意:
1. 共享的數據必須是線程安全的,因為涉及兩個線程的並發訪問。
2. 共享的數據內部的其它對象引用也必須是線程安全的,假如你需要訪問它們。

貼個代碼:
Object shareObject;// init object you need.
var t1 = new System.Threading.Thread(arg =>
{// arg is shareObject
});
var t2 = new System.Threading.Thread(arg =>
{// arg is shareObject
});
t1.Start(shareObject);
t2.Start(shareObject);
 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved