在某些情况下,程序必须等待某个外部操作执行完成,例如输入操作或输出操作等,而在等待时程序无法执行其它任何工作.因此,如果在等待的同时可以运行另一个程序,那么无疑提高了资源的利用率.
专注于为中小企业提供成都网站制作、网站设计、外贸网站建设服务,电脑端+手机端+微信端的三站合一,更高效的管理,为中小企业平川免费做网站提供优质的服务。我们立足成都,凝聚了一批互联网行业人才,有力地推动了上1000家企业的稳健成长,帮助中小企业通过网站建设实现规模扩充和转变。
不同的用户和程序对计算机资源有着同等的使用权.一种高效的运行方式是通过粗粒度的时间片使这些用户和程序能共享计算机资源,而不是一个程序从头运行到尾,然后在启动下一个程序.
通常来说,在计算机多任务时,应该编写多个程序,每个程序执行一个任务并在必要时相互通信,这比只编写一个程序来计算所有的任务更容易实现.
线程安全性可能是非常复杂的,在没有充足的同步情况下,多线程中的执行操作顺序是不可测试,会产生奇怪的问题.
如下代码实例 : UnsafeSequence.java ,1000个线程,并发10次,value++
public class UnsafeSequence { /** 默认值0 */ private static int value = 0; /** 线程执行数量 */ private static int threadCount = 1000; /** 并发数量 */ private static int concurrentCount = 10; /** 线程池 */ private static ExecutorService executor = Executors.newFixedThreadPool(threadCount); /** 信号量(并发数) */ private static Semaphore semaphore = new Semaphore(concurrentCount); /** 和join方法类似 */ private static CountDownLatch countDownLatch = new CountDownLatch(threadCount); public static int getNext () { return value++; } public static void main (String[] args) { // 启动100 个线程 并发10次 去累加 value for (int i = 0; i < threadCount; i++) { executor.execute(() -> { try { // 获取一个许可证 semaphore.acquire(); getNext(); // 计数器减1 countDownLatch.countDown(); // 归还一个许可证 semaphore.release(); } catch (InterruptedException e) { e.printStackTrace(); } }); } // 关闭线程池 executor.shutdown(); try { // 阻塞主线程 直到计数器为0 countDownLatch.await(); System.out.println(value); } catch (InterruptedException e) { e.printStackTrace(); } } }
结果可能是1000或者小于1000,问题在于,如果执行的时机不对,那么两个线程在调用getNext时会得到相同的值,虽然递增运算看起来是单个操作,但是实际上是三个独立的操作,读取value,将value加1,将计算结果写入value,由于多线程交替运行,因此两个线程同时执行读操作,读到了相同的值,结果写入主内存,结果就是不同的线程写入了相同的值.
一个并发应用程序能及时执行的能力称为活跃性,常见的有死锁,饥饿,活锁问题.
性能问题包括多个方面,例如服务器时间过长,响应不够灵敏,吞吐率过低,资源消耗过高,或者伸缩性较低等.