宁波企业免费建站,外贸 wordpress英文,战略网页游戏开服表,信息技术教案 建设我们的网站这篇文章以对比的方式总结Java和.NET多线程编程。基本概念多线程#xff1a;很多开发语言都提供多线程编程支持#xff0c;比如Java#xff0c;C#。并发#xff08;concurrent#xff09;#xff1a;即使对于单核CPU#xff0c;我们也会采用多线程等技术提高service的并… 这篇文章以对比的方式总结Java和.NET多线程编程。基本概念多线程很多开发语言都提供多线程编程支持比如JavaC#。并发concurrent即使对于单核CPU我们也会采用多线程等技术提高service的并发处理能力我们经常说的高并发就是这个意思。并行parallel多个计算机任务能够真正在同一时刻同时执行狭义的讲对同一台计算机在单核CPU时代理论上这是不可能的随着计算机得硬件得发展多核CPU使得这个成为了可能。异步asynchronous programming异步编程可以基于多线程语言层面提供的多线程并不是一定要基于多线程比如说nodejsnodejs的异步编程其实是基于事件驱动和事件循环来实现的。阻塞blocking/非阻塞non-blocking这两个概念更多是出现在IO的场景比如Blocking IOBIO和Non-blocking IONIO其实理解这两个概念我们可以分别类比下面会提到的BlockingQueue和CompletionService。Java在java中多线程编程一般有两种方式使用最原生的API使用concurrent包提供的API1. 使用最原生的API启动一个线程有两种方式继承java.lang.Thread类和实现java.lang.Runnable接口。这两个类都是从java 1.0就开始有了。线程之间同步主要是用synchronized关键字和java.lang.Object的wait()、notify()方法。2. 使用concurrent包提供的API其实concurrent包提供很多功能比如线程池相关类、阻塞队列、集合的线程安全实现等具体可以参考concurent包的官方文档https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/package-summary.html。这里列举一些用过的concurrent包下API的典型例子1) 启动一个线程池把要做的事情放到java.util.concurrent.Callable接口里面实现(Callable不同于Runnable接口的地方是Callable可以有返回)然后把Callable实现类提交给线程池管理同时可以得到一个java.util.concurrent.Future调用Future的get()方法可以获取Callable返回结果。ExecutorService threadPool Executors.newFixedThreadPool(10);ListFutureString futureList new ArrayListFutureString)();
for(int i 0; i 100; i) {FutureString future threadPool.submit(new TaskCallable());futureList.add(future);
}for(FutureString future : futureList) {System.out.println(future.get());
}threadPool.shutdown();
如果有100个Task要执行可以使用java.util.concurrent.CountDownLatch类来等待所有Task都执行完才做下一步操作。2) 上面示例代码中future.get()是一个阻塞动作如果有100个Task有可能后面的Task先执行完这样对后面Task结果的处理就会一直pending在前面Task的future.get()调用上。concurrent包提供了另外一个API - CompletionService可以解决这个问题。实例代码如下ExecutorService threadPool Executors.newFixedThreadPool(10);CompletionServiceString completionService new ExecutorCompletionServiceString(threadPool);for(int i 0; i 100; i) {FutureString future completionService.submit(new TaskCallable());
}for(int i 0; i 100; i) {String result completionService.take().get();System.out.println(result);
}threadPool.shutdown();
3) 控制两个线程执行顺序一个线程等另外一个执行完之后才能继续执行可以用java.util.concurrent.SynchronousQueue比较容易实现而传统的做法则是采用wait/notify。其实SynchronousQueue实现了java.util.concurrent.BlockingQueue接口这个接口还有一些其它的实现类比如java.util.concurrent.ArrayBlockingQueue当我们需要实现一个典型的生产者消费者模型时就可以直接使用这个类。4 HashMap的线程安全实现java.util.concurrent.ConcurrentHashMap。关于ConcurrentHashMap的实现原理可以参考这篇文章漫画什么是ConcurrentHashMap。5) 还有一个经常用到的就是concurrent包下面的java.util.concurrent.locks.Lock接口这个接口有一个实现类java.util.concurrent.locks.ReentrantLock这是一个可重入锁的实现和上面提到的synchronized关键字的作用一样。当然使用Lock和synchronized关键字还是有一些区别的比如Lock可以实现公平锁synchronized则只能是非公平锁。6) java.util.concurrent.atomic包下面提供的原子操作类也经常用到。当我们要实现自增长功能时可以使用java.util.concurrent.atomic.AtomicInteger类这个类实现自增长原子操作的原理是CASCompare And Set算法而不是加锁的方式所以在某些情况下可能会效率高一些。关于CAS算法的原理可以参考这篇文章库存扣多了到底怎么整 | 架构师之路。C# / .NET对比Java里面的多线程编程实现方法.NET里面基本上也都有对用的实现。1) Java中的Thread类和Runnable接口对应.NET里面就是System.Threading.Thread类和System.Threading.ThreadStart委托。2) Java中线程同步主要用synchronized关键字而.NET中则用lock关键字但是lock关键字不能应用到方法上如果要把同步加到方法上可以用System.Runtime.Remoting.Context.Synchronization特性。3) 除了上面提到的语言层面提供的关键字可以用于加锁Java的concurrent包提供了Lock类对应.NET就是System.Threading.Monitor类。4) Java的concurrent包提供了一些原子操作的类比如java.util.concurrent.atomic.AtomicInteger对应.NET里面就是System.Threading.Interlocked。5) Java的concurrent包提供了一些集合的线程安全实现比如java.util.concurrent.ConcurrentHashMap在.NET里面也是类似.NET里面的System.Collections.Concurrent这个namespace下也提供了很多集合的线程安全实现比如System.Collections.Concurrent.ConcurrentDictionary。6) .NET里面使用线程池实现多线程编程例子如下See https://docs.microsoft.com/en-us/dotnet/api/system.threading.threadpool?viewnetcore-3.1using System;
using System.Threading;public class Example
{public static void Main() {// Queue the task.ThreadPool.QueueUserWorkItem(ThreadProc);Console.WriteLine(Main thread does some work, then sleeps.);Thread.Sleep(1000);Console.WriteLine(Main thread exits.);}// This thread procedure performs the task.static void ThreadProc(Object stateInfo) {// No state object was passed to QueueUserWorkItem, so stateInfo is null.Console.WriteLine(Hello from the thread pool.);}
}
7) .net 4.0新增的TAPtask-based asynchronous pattern不需要显示操作线程CLR负责管理线程的分配只需要关注Task如下using System;
using System.Threading;
using System.Threading.Tasks;namespace ConsoleApp1
{class Program2{static void Main(string[] args){Console.WriteLine(current thread: Thread.CurrentThread.ManagedThreadId);// Construct a started task using Task.Run.String taskData delta;Task t3 Task.Run(() {Console.WriteLine(Task{0}, obj{1}, Thread{2}, Task.CurrentId, taskData, Thread.CurrentThread.ManagedThreadId);Thread.Sleep(1000 * 10000);});// Wait for the task to finish.//t3.Wait();Task t2 Task.Run(() {Console.WriteLine(Task{0}, obj{1}, Thread{2}, Task.CurrentId, taskData, Thread.CurrentThread.ManagedThreadId);});// Wait for the task to finish.t2.Wait();Console.WriteLine(end);}}
}
在.net 4.5之后又新增了async/await关键字这种方式基于TAP通过这种方式可以方便的实现Task完成之后的callback逻辑比如上面例子中想在t3执行完了之后再做一些逻辑需要调用t3.wait()或者调用Task.WaitAll()方法。有async/await关键字之后可以很方便的实现如下using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;namespace ConsoleApp1
{class Program{static void Main(string[] args){TestMain();}static void TestMain(){Console.Out.Write(Start\n);GetValueAsync();Console.Out.Write(End\n);Console.ReadKey();}static async Task GetValueAsync(){await Task.Run((){Thread.Sleep(1000);for(int i 0; i 5; i){Console.Out.WriteLine(String.Format(From task : {0}, i));}});Console.Out.WriteLine(Task End);}}
}
上面Console.Out.WriteLine(Task End);这行代码即是Task执行完成之后才执行的逻辑。这个有点像javascript里面的Promise.8) .net 4.0里面还提供了并行编程的一些功能比如System.Threading.Tasks.Parallel。所谓并行编程狭义的讲就是说可以充分利用现在计算机CPU多核的优势让运算任务在多个核上同时并行执行。更多的可以参考https://docs.microsoft.com/en-us/dotnet/standard/parallel-programming/。相关阅读从Java转向.NET/C#Are You OK?