多线程学习一(多线程基础)

前言

多线程、单线程、进程、任务、线程池...等等一些术语到底是什么意思呢?到底什么是多线程?它到底怎么用?我们一起来学习一下多线程的处理

如何理解

进程:进程是给定程序当前正在执行的实例(操作系统的一个基本功能就是管理进程)

线程:线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位

单线程程序是仅包含一个线程的进程。多线程程序的进程则包含两个或更多的线程

线程安全:在多线程程序中运行时具有正确的表现,就说代码是线程安全的

任务:任务是可能有高延迟的工作单元,目的是生成一个结果值,或者产生想要的效果

线程池:线程池是多个线程的集合,也是决定如何向线程分配工作的逻辑

多线程处理的目的和方式

 多线程处理主要用于两个方面:

  1、实现多任务

2、解决延迟

其中主要还是解决延迟问题:例如导入一个大文件的时候需要较长的时间,为了允许用户随时点击取消,开发者创建一个额外的线程来执行导入,这样就可以随时点击取消,而不是直接冻结UI直至导入完成。

当然,如果有足够的内核使得每一个线程都能分配到一个内核的话,那么每个线程就都使用自己各自的CPU。但是如今虽然有了多核机器,但是线程数任然大于内核的数量。

为了解决这一粥(CPU内核)少僧(线程)多的矛盾,操作系统通过称为时间分片的机制来模拟多个线程并发运行。操作系统以极快的速度从一个线程切换到另一个线程,给人的感觉就是所有的线程都在同时执行

时间片:处理器在切换到下一个线程之前,执行一个特定的线程的时间周期称之为时间片或量子

上下文切换:在一个给定的内核中改换执行线程的动作称为上下文切换

不管是真正的多核并行运行还是使用时间分片的机制来模拟,我们说“一起”进行的两个操作是并发的。并行编程是指将一个问题分解成较小的部分,并异步的发起对每个部分的处理,使它们能并发地得到处理。

其中我们也需要考虑的是性能问题,不要产生一种误导就是多线程的代码会更快,多线程知识解决处理器受限的问题。同时我们需要注意性能问题

多线程处理遇到的问题

  

写一个多线程程序既复杂又困难,因为在单线程程序中许多成立的假设在多线程中变得不成立了,其中包括原子性、竞态条件、复杂的内存模型以及死锁

1、大多数操作不是原子性的

int Balance=10;
int Money=6;
if(Balance>Money)
 {
     Balance-=Money;
 }    

在这段代码中,如果出现两个线程都拿到Balance(当前余额)并且都进入了if中,第一个拿走了Money(取走的金额),然后第二个没有经过验证继续执行了Balance-=Money的操作,最后得出的结果是Balance剩下-2。这就导致了出现错误。

2、竞态条件造成的不确定性

什么是竞态条件

官方的定义是如果程序运行顺序的改变会影响最终结果,这就是一个竞态条件(race condition).

Runnable r1 = () -> { // do something };
Runnable1 r2 = () -> { // do another thing };
Thread producer = new Thread(new ThreadStart(Runnable));
Thread producer1 = new Thread(new ThreadStart(Runnable1));

producer.Start();
producer1.Start();

两个线程同时把一个类的静态成员做50词自增加1的操作,即

SomeClass.someMember++;

写在两个线程中,都运行50次,运行结束以后用主线程去取这个变量的值几乎不可能是100. 有的时候是97,有的时候是98,这是用来说明竞态条件的最有效例子。

3、内存模型的复杂性

假设两个线程在两个不同的进程中运行,但要访问同一个对象中的字段,目前的处理器不会每次都去访问主内存,相反访问的是处理的“高速缓存”中生成的一个本地副本,这个缓存会定时的与主内存同步,这就意味着这两个不同进程中的线程以为自己读取到的是相同的位置,实际读取到的不是那个字段实时更新的,造成两个线程获取的字段结果不一致。

4、锁定造成死锁

当然肯定有办法解决非原子性,防止竞态条件,并且确保处理器的高速缓存在必要时进行同步的。解决这些问题的主要机制是lock语句,这个语句就是将一部分代码设置为“关键”代码,一次只有一个线程能执行它,如果多个线程需要访问它,操作系统只允许进入一个,其他的将被挂起。

当然锁也有问题,加入不同的线程以不同的顺序获取锁,就可能造成死锁,这样的结果就是你等着我释放锁,我等着你释放锁。此时只有对方释放了锁之后才能继续运行,线程阻塞,造成了这段代码的彻底死锁

既然锁可以解决前三个问题,但是可能会出现死锁的问题。那么我们改如何避免或解决死锁的问题呢?

如何避免死锁

既然加入不同的线程以不同的顺序获取锁可能造成死锁,那么我们只有确保所有的线程都是按照相同的顺序获得锁,那么死锁就不会发生。

class Program
    {
        private static object objA = new object();
        private static object objB = new object();
        static void Main()
        {
            Program a = new Program();
            Thread th = new Thread(new ThreadStart(a.Lock1));
            th.Start();

            lock (objB)
            {

                Console.WriteLine("我是objB,想获取objA");
                lock (objA)
                {
                    Console.WriteLine("死锁了");
                }
            }

            Console.WriteLine("死锁了");
            Console.WriteLine();
        }

        public void Lock1()
        {

            lock (objA)
            {
                Thread.Sleep(500);
                Console.WriteLine("我是objA,想获取objB");
                lock (objB)
                {
                    Console.WriteLine("死锁了");
                }
            }
        }
    } 

上面是获取锁的顺序不恰当而导致死锁的例子。如果把其中一个获取锁的位置改变一下就不会造成死锁了,例如在Lock1中先获取objB再获取objA的话就不会造成死锁了。所有我们平时在使用lock时一定得确保锁的顺序,不然很容易造成死锁的。

      本文参考c#本质论6.0多线程处理

原文地址:https://www.cnblogs.com/hulizhong/p/10680127.html

时间: 2024-11-16 16:37:15

多线程学习一(多线程基础)的相关文章

C#多线程学习(一) 多线程的相关概念

什么是进程?    当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源.而一个进程又是由多个线程所组成的. 什么是线程?    线程是程序中的一个执行流,每个线程都有自己的专有寄存器(栈指针.程序计数器等),但代码区是共享的,即不同的线程可以执行同样的函数. 什么是多线程?    多线程是指程序中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的任务,也就是说允许单个程序创建多个并行执行的线程来完成各自的任务. 多线程的好处:    可以提

C#多线程学习(一) 多线程的相关概念(转)

什么是进程?当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源.而一个进程又是由多个线程所组成的. 什么是线程?线程是程序中的一个执行流,每个线程都有自己的专有寄存器(栈指针.程序计数器等),但代码区是共享的,即不同的线程可以执行同样的函数. 什么是多线程?多线程是指程序中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的任务,也就是说允许单个程序创建多个并行执行的线程来完成各自的任务. 多线程的好处:可以提高CPU的利用率.在多线程程序中

java多线程学习之——多线程中几种释放锁和不释放锁的操作

在学习java多线程这一块知识的时候,遇到了很多个关于线程锁什么时候释放的问题,现总结几种释放锁和不释放锁的操作如下: 不释放锁: 线程执行同步代码块或同步方法时,程序调用Thread.sleep(Long l).Thread.yield()方法暂停当前线程的执行 线程执行同步代码块时,其它线程调用该线程suspend()方法将该线程挂起,该线程不会释放锁(同步监视器) 尽量避免使用suspend()和resume()来控制线程 释放锁: 当前线程的同步方法.同步代码块执行结束 当前线程的同步方

多线程学习之多线程访问共同资源(队列,多线程,锁机制)实例

模拟场景:main方法为网络请求线程(也叫生产者线程),在网络请求线程中开启四个线程(消费者线程),进行高效处理队列中的共同资源(生产者线程生产的共同资源),等待资源处理完毕,网络请求线程执行结束,响应客户端. 消费者线程体 1 /** 2 * 3 */ 4 package com.benxq.Queue; 5 6 import java.text.SimpleDateFormat; 7 import java.util.Date; 8 import java.util.concurrent.B

Linux程序设计学习笔记----多线程编程基础概念与基本操作

转载请注明出处,http://blog.csdn.net/suool/article/details/38542543,谢谢. 基本概念 线程和进程的对比 用户空间资源对比 每个进程在创建的时候都申请了新的内存空间以存储代码段\数据段\BSS段\堆\栈空间,并且这些的空间的初始化值是父进程空间的,父子进程在创建后不能互访资源. 而每个新创建的线程则仅仅申请了自己的栈,空间,与同进程的其他线程共享该进程的其他数据空间包括代码段\数据段\BSS段\堆以及打开的库,mmap映射的文件与共享的空间,使得

多线程学习-基础(十二)生产者消费者模型:wait(),sleep(),notify()实现

一.多线程模型一:生产者消费者模型   (1)模型图:(从网上找的图,清晰明了) (2)生产者消费者模型原理说明: 这个模型核心是围绕着一个"仓库"的概念,生产者消费者都是围绕着:"仓库"来进行操作,一个仓库同时只能被一个生产者线程或一个消费者线程所操作,synchronized锁住的也是这个仓库,仓库是一个容器,所以会有边界值,0和仓库可存放上限,在这个上限内,可以设置多种级别,不同的级别可以执行不同的策略流程. (3)本案例使用知识点: Thread.curre

Java多线程学习(吐血超详细总结)

林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka 目录(?)[-] 一扩展javalangThread类 二实现javalangRunnable接口 三Thread和Runnable的区别 四线程状态转换 五线程调度 六常用函数说明 使用方式 为什么要用join方法 七常见线程名词解释 八线程同步 九线程数据传递 本文主要讲了java中多线程的使用方法.线程同步.线程数据传递.线程状态及相应的一些线程函数用法.概述等. 首先讲一下进程和线程

Java多线程学习

写在前面的话:此文只能说是java多线程的一个入门,其实Java里头线程完全可以写一本书了,但是如果最基本的你都学掌握好,又怎么能更上一个台阶呢?如果你觉得此文很简单,那推荐你看看Java并发包的的线程池(Java并发编程与技术内幕:线程池深入理解),或者看这个专栏:Java并发编程与技术内幕.你将会对Java里头的高并发场景下的线程有更加深刻的理解. 目录(?)[-] 一扩展javalangThread类 二实现javalangRunnable接口 三Thread和Runnable的区别 四线

多线程学习总结

最近在搞一个多线程上传图片数据的工具,遇到了很多坑,于是就趁晚上下班前总结下学习心得.多线程其实很简单,只不过要多练习,总结才能吸收消化,否则,学了不会用也是瞎扯. 先把基础巩固好,然后再不断在工作中实践.学习多线程从以下几个方面入手比较快. 1.多线程概念 2.为什么要使用多线程. 3.使用多线程相比单线程有什么好处 4.多线程使用时,线程安全怎么控制 5.线程池对于多线程有哪些好处 6.线程池的几种策略,优缺点,项目中怎么使用.