これに代わるアプローチを提案したいと思います。
多数の BackgroundWorker を作成するのではなく、1 つだけ作成し、その DoWork() 内Parallel.ForEach()で文字列を逆にするために使用できます。
そうすれば、スレッド数が最適に処理されます。
UI スレッドのロックを回避するには、BackgroundWorker を使用する必要があります。
コンソール アプリで実行されるコンパイル可能な例を次に示します。
using System;
using System.Linq;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
    class Program
    {
        static void Main()
        {
            string[] data = Enumerable.Range(10000, 100).Select(i => i.ToString()).ToArray();
            Parallel.ForEach(data, (item, state, index) => data[index] = Reverse(item));
            foreach (var s in data)
                Console.WriteLine(s);
        }
        public static string Reverse(string s)
        {
            char[] charArray = s.ToCharArray();
            Array.Reverse(charArray);
            return new string(charArray);
        }
    }
}
また、.Net 4.5 を使用している場合は、新await/async機能を使用して BackgroundWorker の使用を完全に回避できます。
たとえば、既定の Windows フォーム アプリケーションを作成し、その上に Label という名前label1のボタンと という名前のボタンをドロップしますbutton1。次に、Form1.cs ファイルを次のように変更します。
using System;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            data = Enumerable.Range(10000, 1000000).Select(i => i.ToString()).ToArray();
        }
        async void button1_Click(object sender, EventArgs e)
        {
            label1.Text = "Reversing strings...";
            await doWork();
            label1.Text = "Reversed strings.";
        }
        Task doWork()
        {
            return Task.Factory.StartNew(() => Parallel.ForEach(data, (item, state, index) => data[index] = reverse(item)));
        }
        static string reverse(string s)
        {
            char[] charArray = s.ToCharArray();
            Array.Reverse(charArray);
            return new string(charArray);
        }
        readonly string[] data;
    }
}
ボタンをクリックすると、文字列が逆になっている間、UI は応答し続けます。