专栏名称: 养码场
养码场,一个技术人职场社交平台。 现有“养码人”80000+,覆盖JAVA/PHP/iOS/测试/运维等领域。80%级别在P6及以上,含P9技术大咖30人,技术总监和CTO 500余人。
目录
相关文章推荐
生态梦网  ·  精品小班!生态城美术中高考培训招生啦 ·  昨天  
FM1007福建交通广播  ·  宇树科技携两款机器人亮相2025GDC ·  2 天前  
FM1007福建交通广播  ·  宇树科技携两款机器人亮相2025GDC ·  2 天前  
生态梦网  ·  超245亿!生态城新能源汽车产业强势崛起 ·  3 天前  
51好读  ›  专栏  ›  养码场

端午前福利!Java\/Python实体书赠送

养码场  · 公众号  ·  · 2019-06-06 16:36

正文

好久没给大家送福利了,今天来一波图书福利( 拉至文末


本篇文章分享的是多线程的锁机制。


多线程编程访问共享变量时会出现问题,但是多进程编程访问共享变量不会出现问题。因为多进程中,同一个变量各自有一份拷贝存在于每个进程中,互不影响,而多线程中,所有变量都由所有线程共享。


多个进程之间对内存中的变量不会产生冲突,一个进程由多个线程组成,多线程对内存中的变量进行共享时会产生影响,所以就产生了死锁问题 ,怎么解决死锁问题是本节主要介绍的内容。


1、变量的作用域


一般在函数体外定义的变量称为全局变量,在函数内部定义的变量称为局部变量。全局变量所有作用域都可读,局部变量只能在本函数可读。函数在读取变量时,优先读取函数本身自有的局部变量,再去读全局变量。


内容如下:



运行脚本得到以下结果。



如果注释掉change()函数里的 global v1,那么得到的返回值是。



在本例中在change()函数外定义的变量balance是全局变量,在change()函数内定义的变量num是局部变量,全局变量默认是可读的,可以在任何函数中使用,如果需要改变全局变量的值,需要在函数内部使用global定义全局变量,本例中在change()函数内部使用global定义全局变量balance,在函数里就可以改变全局变量了。


在函数里可以使用全局变量,但是在函数里不能改变全局变量。想实现多个线程共享变量,需要使用全局变量。在方法里加上全局关键字 global定义全局变量,多线程才可以修改全局变量来共享变量。


2、多线程中的锁


多线程同时修改全局变量时会出现数据安全问题,线程不安全就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据。在本例中我们生成2个线程同时修改change()函数里的全局变量balance时,会出现数据不一致问题。


本案例文件名为PythonFullStackChapter03 hreadDemo03.py,内容如下。



运行以上脚本,当2个线程运行次数达到500000次时,会出现以下结果。



在本例中定义了一个全局变量balance,初始值为100,当启动2个线程后,先加后减,理论上balance应该为100。线程的调度是由操作系统决定的,当线程t1和t2交替执行时,只要循环次数足够多,balance结果就不一定是100了。从结果可以看出,在本例中线程t1和t2同时修改全局变量balance时,会出现数据不一致问题。


值得注意


在多线程情况下,所有的全局变量有所有线程共享。所以,任何一个变量都可以被任何一个线程修改,因此,线程之间共享数据最大的危险在于多个线程同时改一个变量,把内容给改乱了。


在多线程情况下,使用全局变量并不会共享数据,会出现线程安全问题。线程安全就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。


不会出现数据不一致,在单线程运行时没有代码安全问题。写多线程程序时,生成一个线程并不代表多线程。在多线程情况下,才会出现安全问题。

针对线程安全问题,需要使用”互斥锁”,就像数据库里操纵数据一样,也需要使用锁机制。某个线程要更改共享数据时,先将其锁定,此时资源的状态为“锁定”,其他线程不能更改;直到该线程释放资源,将资源的状态变成“非锁定”,其他的线程才能再次锁定该资源。互斥锁保证了每次只有一个线程进行写入操作,从而保证了多线程情况下数据的正确性。


互斥锁的核心代码如下:



如果要确保balance计算正确,使用threading.Lock()来创建锁对象lock,把 lock.acquire()和lock.release()加在同步代码块里,本例的同步代码块就是对全局变量balance进行先加后减操作。


当某个线程执行change()函数时,通过lock.acquire()获取锁,那么其他线程就不能执行同步代码块了,只能等待知道锁被释放了,获得锁才能执行同步代码块。由于锁只有一个,无论多少线程,同一个时刻最多只有一个线程持有该锁,所以修改全局变量balance不会产生冲突。改良后的代码内容如下。



在例子中2个线程同时运行lock.acquire()时,只有一个线程能成功的获取锁,然后执行代码,其他线程就继续等待直到获得锁位置。获得锁的线程用完后一定要释放锁,否则其他线程就会一直等待下去,成为死线程。


在运行上面脚本就不会产生输出信息,证明代码是安全的。把 lock.acquire()和lock.release()加在同步代码块里,还要注意锁的力度不要加的太大了。第一个线程只有运行完了,第二个线程才能运行,所以锁要在需要同步代码里加上。


最后,端午前最后一波福利


养码场联合北京大学出版社为大家送出下面两本书。


《Python 3 数据分析与机器学习实战》


1、全新:本书理论、技术与案例基于全新的Python 3.X。

2、实战:跳脱纯理论讲述,案例贯穿全书,包括等人工智能、机器学习、深度学习、网络爬虫等项目实战。

3、丰富:大量的教学资源:29个大型真实项目案例,94节同步微视频讲解,30小时Python 3语法教学视频。

https://item.jd.com/12407729.html



《Java核心技术及面试指南》

1、全面:本书作者团队阵容强大,既有架构师、培训师,又有面试官,分别从自身经验出发讲解工作中遇到的痛点。

2、实用:本书将相关知识的系统整合,符合现在Java的主流应用,拒绝全面不实用;本书知识点主要围绕技术升级和面试技巧展开,让你在升级专业知识的同时更能顺利通过面试。

3、丰富:本书附带Java Core常用知识点的视频和面试题,并且内容会不断更新。

https://item.jd.com/12421187.html








请到「今天看啥」查看全文