2015年11月20日20:51:55
Java高级部分–线程重点总结
作者:数据分析玩家
本章重点:线程的概念、线程同步的概念
【线程在面试的时候会问,但是线程在开发的时候用的并不多】
多线程的优势:
1>多线程打破了传统的编程模式
2>多线程编程简单,效率高,能直接共享数据和资源
3>适合于开发服务程序【如web服务,聊天服务】
线程的概念:
线程是一个程序里的不同执行路径,即线程就是不同的执行路径
多线程的概念:按照传统的理解,程序中的代码应该是一行一行的执行,上一行代码若没有执行完毕,下一行代码则不会执行,而多线程是若上一行代码没有执行完毕,下面的代码就可以执行了,两行代码可以交替的执行,即一个程序中的好多代码由Cpu来交替的进行执行【所谓同时执行就是交替的执行,也就是一个程序的流程在某一个地方单独的开辟了一个分支,两个分支不停的占用cpu来交替的进行执行,这就是多线程】
如何理解多线程:
在多线程中,尽管cpu在多个线程之间来回的进行切换,但对于某个线程而言,虽然代码是断断续续的从上往下进行执行,但是每个线程中的代码仍然是按照顺序进行执行的,多个线程代码彼此之间的 相互打乱只是一种假象
多线程官方概念:
以前所编写的程序,每个程序都有一个入口,一个出口以及一个顺序执行的序列,在程序执行过程中的任何指定时刻,都只有一个单独的执行点。
事实上,在单个程序的内部是可以在同一时刻进行多种运算的,这就是所谓的多线程
创建线程的两种方式:
1>通过继承Thread类来创建多线程
2>通过实现Runnable接口来创建多线程
两种方式的比较:
1>若处理的是不同的资源,两种创建线程的方式均可
2>若处理的是相同的资源,实现资源的共享,只能使用实现Runnable接口的方式来创建线程
【通过实现Runnable接口创建线程只需要定义一个对象,用这个对象可以造出很多个线程,并且这些线程可以共享同一个资源;而通过继承Thread类若想共享同一个资源,必须借助static等语法知识】
综上:几乎所有的多线程程序都是通过实现Runnable接口的方式来完成的,这中方式具有无可比拟的优势
创建线程2种方式语法的比较:
1>在代码块中都要重写run方法
2>都是通过start方法来启动run方法
3>run方法原本是Runnable接口特有的,但是Thread类中也有;start方法是Thread类特有的,但是Runnable接口没有,因为接口中的方法不能有方法体
创建线程的注意问题:
1>aa.start()与aa.run()的联系:aa.start()会自动调用run()方法,start表示启动的意思,若直接写aa.run()就是传统的调用,不会开辟新的线程,只有写的是start才意味这开辟一个新的线程,这个新的线程会自动调用aa对象里面的run()方法
2>start关键字的含义:
启动一个新的线程;
执行这个线程对应的run()方法里面的代码
【Thread t1 = new Thread(aa);
t1.start();
所谓t1线程启动,指的是t1线程所对应的run()方法
进行执行】
3>Thread类中的start()方法的功能就是创建一个新的线程,并自动调用线程中的run()方法,即这个重任由Thread类中的start()来完成,注意:直接调用run()方法是不会创建一个新的线程的
4>创建一个线程由start方法来完成,执行一个线程由run方法来完成:即执行一个线程就是执行该线程中的run()方法中的代码
2015年11月21日10:05:06
5>执行完aa.start()之后并不表示aa所对应的线程就一定会立即得到执行,aa.start()执行完之后只是表明了aa线程具有了可以被Cpu执行的资格,但由于想抢占cpu执行的线程很多,Cpu并不一定会立即去执行aa所对应的线程,因为此时aa所对应的线程将处于阻塞状态
【一个线程对应3种 不同的状态:就绪状态、运行状态、阻塞状态】
6>一个Thread对象只能开辟一个线程【所谓一个线程就是这个线程中有一个run()方法,这个run()方法中的代码在不停的执行】
Cpu相关知识
1>从本质上来讲,cpu不可能在一个时间点上执行多个线程,只是因为cpu执行速度很快,所以cpu看似同时在执行很多个线程,多个线程之间只是交替的占用cpu进行执行,所谓cpu很快指的是cpu单个时间切换的速度很快
2>java虚拟机当中有一个线程调度器,它里面有相应的方法控制哪个线程先执行,哪个线程后执行,但是最终哪个线程先执行,则是由操作系统进行控制的,java虚拟机不能够越过操作系统直接对硬件cpu进行控制,因此实际开发中不能够依赖线程优先级来决定线程运行次序
Thread类中的常用方法
currentThread():返回当前线程的引用
getName():返回当前线程的名字
setName():设置当前线程的名字
sleep():暂停当前运行中的线程,使之进入阻塞状态,待经过指定的“延迟时间”后在醒来并转入到就绪状态,不是运行状态。
aa.wait():将执行aa.wait()的当前线程转入阻塞状态,让出cpu的控制权;释放对aa对象的锁定
aa.notify():假设执行aa.notify()的当前线程为t1,如果当前时刻有其它线程因为执行了aa.wait()而陷入阻塞状态,则叫醒其中的一个,注意叫醒的不是本线程【t1】
【所谓叫醒某个线程就是另该线程从因为wait而陷入阻塞的状态转入就绪的状态】
aa.notifyAll():叫醒其它所有因为执行了aa.wait()而陷入阻塞的状态的线程
This.notify()的功能:
1>不是叫醒正在执行this.notify()这个语句的当前线程,因为当前线程正在执行,不存在所谓叫醒叫不醒的问题,而是叫醒一个正在wait this 对象的当前线程,如果有多个线程正在wait this 对象,可以通过aa.notifyAll()语句叫醒所有线程
线程同步问题:
线程同步问题产生的原因:
因为第1行到第6行的代码他们不是一个不可分割的整体,cpu可以在第1行到第6行的任意一个时间点上切换到另外一个线程进行执行,所以出现了线程的同步问题
考虑线程同步问题的必要性:当多个线程操作同一个资源,并且要求这些操作中的若干个步骤不能被中断的时候,这个时候就需要考虑线程同步的问题,否则的话就不能保证共享数据的一致性,也就不能保证程序的正确性
解决思路:线程同步是通过synchronized来实现的
【在java当中,通过synchronized机制,保证当A线程执行1行到6行的代码时,B线程不能在执行这些代码,即保证这些关键的步骤在被某一个线程访问的时候,另一个线程不能在进行访问,除非当前线程执行完毕】
Synchronized的用法:
1>synchronized用来修饰某个方法【默认锁定的是this】
若synchronized修饰一个方法,当某个线程执行这个方法时,线程霸占的是该方法的this指针所指向的某个对象,即线程霸占的是正在调用该方法的对象
【霸占的专业术语叫锁定,霸占住的那个对象的专业术语叫监听器】
2>synchronized用来修饰方法内部的某个代码块
格式:synchronized(类对象名 aa)
{
同步代码块;
}
整体结果:一个线程正在操作某个资源的时候,将不允许其它线程操作该资源,即一次只允许一个线程处理该资源
【即此时这些内部代码块,在某一个时间点上只允许有一个线程来执行,这个线程若没有执行完毕,其余的线程就不能执行这块代码,尽管cpu仍在不停的切换,但是并不执行】
摘要:
网站:http://www.cnblogs.com/luxiaoxun/p/3870265.html
http://www.cnblogs.com/gw811/archive/2012/10/15/2724882.html