小结:
1.每一个线程一定会有一个名字,如果用户没有指定名字,系统会为线程指定一个名字(Thread-1/2/3…)。
2.当线程的run方法结束的时候该线程完成任务。
3.我们程序员无法控制线程调试的顺序。CPU根据当时的状态自行决定。
4.线程的几种状态。
执行结果分析:其中的一种,其他可自行分析。
in work2,g_num=102 此时work1在阻塞状态,work1和work2都已完成第一次加1操作。
in work1,g_num=103 此时work2在阻塞状态,work2完成了第二次加1操作,work1完成 第一次加1操作。
in work2,g_num=104 此时work1在阻塞状态,work1和work2都已完成第二次加1操作。
in work1,g_num=105 此时work2在阻塞状态,work2完成了第三次加1操作,work1完成
第二次加1操作。
in work2,g_num=106 此时work1在阻塞状态,work1和work2都已完成第三次加1操作。
in work1,g_num=106 此时work2在死亡状态,work1和work2都已完成第三次加1操作。
(1)功能:
进程:能够完成多任务,比如在一台能够同时运行多个QQ:
线程:能够完成多任务,比如一个QQ中的多个聊天窗口。
(2)定义:
进程是系统进行资源分配和调试的一个独立单位。
线程是进程的一个实体,是CPU调用和分派的基本单位,它是比进程更小的能独立运行 的基本单位。
线程自己基本上不拥有系统资源,但是它可以与同属于一个进程的其它线程共享进程所 拥有的全部资源。
一个程序至少有一个进程,一个进程至少有一个线程,线程的划分尺度小于进程(资 源比进程少),使得多线程程序并发性更高。进程在执行过程中拥有独立的内存单元, 而多个线程共识这段儿内存空间。线程不能独立运行,必需依存进程。
线程和进程在使用上各有优势和缺点:线程的执行开销小,但不利于资源的管理和 保存。进程正好相反。
先看一个例子:假设两个线程t1\t2都要对num进行操作(增1),t1和t2都各自对num修改10次,num最终的值应该为20.紧接着我们把10次改为100000000次,由于多线程访问,有可能不一样的结果。
问题分析:
问题产生的原因就是没有控制多个线程对同一资源的访问,对数据造成破坏,
使得线程运行的结果达不到预期。这种现象我们称为“线程不安全”
解决思路:
1.t1被调用的时候,获取g_num=0, 然后上一把锁,即不允许其它线程操作g_num。
2.对num进行加1
3.解锁,g_num = 1,其它的线程就可以使用g_num的值,而且g_num的值不是原来的0
4.同理其它线程在对num进行修改时,都要先上锁,处理完成后再解锁。
在上锁的整个过程中,不允许其它线程访问,保证了数据的正确性。
解决方案:互斥锁
互斥锁:当多个线程几乎同时修改某一个共享数据的时候,需要进行同步控制。线程同步能够保证多个线程安全访问“竞争资源”,最简单的同步机制就是引用互斥锁。互斥锁为资源引入一个状态:锁定/非锁定状态。某个线程要更改共享数据时,先将其锁定,此时资源状态为“锁定”,其它线程不能更改;直到当前线程释放资源,将资源变成"非锁定"状态,其它的线程才能再次锁定该资源。互斥锁保证了每次只有一个线程进行“写操作”,从而保证多个线程数据正确性。
在threading模块当中,定义一个Lock类,可以方便的处理锁定:
Lock类的使用示例:
分析:一个变量被锁住之后,必须解锁才可以重新使用。否则不可使用。而且锁住之后只能运行一个线程,降低了效率。
分析:上锁/解锁过程。
当一个线程调用锁的acquire()方法获取锁时,锁就进行“锁定(Locked)”状态。每次只有一个线程可以获得这个锁。如果此时另一个线程试图获取锁中的资源,该线程就会变为“阻塞”状态。直到拥有锁的那个线程执行release(),锁就变成“非锁定(Unlocked)”状态。
线程调试程序从处于同步阻塞状态的线程中选择一个来获得锁,并使得该线程进入“运行(running)”状态。
1.确定了某段代码只能由一个线程从头到尾完整地执行。
2.全局变量的安全
锁的坏处:
1.阻止了多线程的并发执行,包含锁的某段代码实际上只能以单线程模块执行,效率大大地下降了。
2.由于可以存在多个锁,不同的线程持有不同的锁,并试图获取对方持有的锁的时,可能会造成“死锁”。
死锁的两种情况:
(1)同一个线程先后两次调用lock,在第二次调用时,由于锁已经被自己占用,该线程会挂起等待自己释放锁,由于该线程已被挂起而没有机会释放锁,因此 它将一直处于挂起等待状态,变为死锁;
(2)线程A获得了锁1,线程B获得了锁2,这时线程A调用lock试图获得锁2,结果是需要挂起等待线程B释放锁2,而这时线程B也调用lock试图获得锁1,结果是需要挂起等待线程A释放锁1,于是线程A和B都在等待对方释放自己才释放,从而造成两个都永远处于挂起状态,造成死锁。
死锁概念:在线程间共享多个资源的时候,如果两个线程分别占有一部分资源并且同时等待对方的资源时,就会造成死锁。尽管死锁很少发生,但一旦发生就会造成应用的停止响应。