多线程详细笔记含代码.docx
《多线程详细笔记含代码.docx》由会员分享,可在线阅读,更多相关《多线程详细笔记含代码.docx(14页珍藏版)》请在冰点文库上搜索。
多线程详细笔记含代码
java知识点总结
@多进程
1.基本概念:
程序、进程、线程
程序(program):
一组指令的集合,一段静态代码。
(完成特定任务的代码,由某种语言编写)
进程(process):
是一个程序的执行过程(即正在运行的程序)。
是个动态过程:
有他自身的产生、存在和消亡的过程。
PS:
例子:
如运行中的QQ,运行中的MP3播放器。
程序和进程区别:
程序时静态的,进程是动态的。
线程(thread):
进程可细分为线程,是一个程序内部的一条执行路径
PS:
若一个程序可同一时间执行多个线程,就是支持多线程的
何时需要多线程:
[1]程序需要同时执行多个任务;
[2]程序需要实现一些需要等待的任务的时候(如用户输入、文件读写操作、网络操作、搜索等。
);
[3]需要一些后台运行的程序时-守护线程。
(如垃圾回收线程)
2.多线程的创建和使用
(1)线程的创建(2种方法)
[1]第一种创建:
继承于java.lang.Thread类(无需插包)
例子:
//1.创建一个继承于Thread的类
classSubThreadextendsThread{
publicvoidrun(){//2.重写Thread类的run()方法,方法内实现子线程内要完成的功能
for(inti=0;i<100;i++){
System.out.println(i);
}
}
}
publicclassTestThread{
publicstaticvoidmain(String[]args){
SubThreadst=newSubThread();//3.创建一个子类对象
st.start();//4.调用线程的start()方法(两个作用:
启用此线程,调用相应的run方法)
}
}
注意:
Thread类常用的方法及作用
-1-start()方法。
启动线程并执行相应的run方法
-2-run()方法。
子线程要执行的代码放到run()方法中
-3-currentThread()。
静态的,调用当前线程(相当于一个当前线程的对象,都是在自己的线程里才用的)。
(读音:
克(饿)‘润特)
-4-getName()方法。
获得此线程的名字
-5-setName()方法。
设置此线程的名字
-6-yield()方法。
CPU暂时释放该线程的执行权(也可能在下一次抢到执行权)(读音:
亿奥的)
-7-join()方法(该方法有异常,需要trycatch,使用的时候都是调用其他线程,st1.join())。
在A线程调用B线程的join方法时,A线停止运行,直至B线程执行结束,A线程再接着join之后的方法继续执行。
-8-isAlive()方法。
判断当前线程是否还存活(返回时布尔值)。
-9-sleep(longa)方法(需要抛trycatch异常)。
显示让当前线程睡眠a毫秒。
-10-线程通信:
wait()、notify()、notifyAll()
线程优先级的方法(优先级大的线程抢到CPU的概率大点)
-11-setPriority():
设置线程优先级(最小1,最大10(也可表示Thread.MAX_PRIORITY),正常5)(读音:
破ruai欧瑞踢)
-12-getPriority():
返回线程优先值
例子
#例子1:
currentThread()、getName()、setName()
classSubThread1extendsThread{
publicvoiarun(){
for(inti=0;i<10;i++){
System.out.println(Thread.currentThread().getName()+”:
”+i);//调用当前线程的名字,当前线程是st1
}
}
}
publicclassTestThread1{
publicstaticvoidmain(String[]args){
SubThread1st1=newSubTread1();
st1.setName(“子线程1”);//设置线程st1的名字
st1.start();//开始st1线程
Thread.currentThread().setName(“主线程”);//设置当前线程的名字(当前线程时主线程)
for(inti=0;i<10;i++){
System.out.println(Thread.crrentThread().getName()+”:
”+i);
}
}
}
#例子2:
yield()
classSubThread1extendsThread{
publicvoiarun(){
for(inti=0;i<10;i++){
System.out.println(Thread.currentThread().getName()+”:
”+i);
}
}
}
publicclassTestThread1{
publicstaticvoidmain(String[]args){
SubThread1st1=newSubTread1();
st1.setName(“子线程1”);
st1.start();
Thread.currentThread().setName(“主线程”);
for(inti=0;i<10;i++){
System.out.println(Thread.crrentThread().getName()+”:
”+i);
if(i%10==0){
Thread.crrentThread().yield();//当i是10的倍数的时候,主线程暂时释放CPU的执行权
}
}
}
}
#例子3:
join(),该方法有异常,需要trycatch
classSubThread1extendsThread{
publicvoiarun(){
for(inti=0;i<10;i++){
System.out.println(Thread.currentThread().getName()+”:
”+i);
}
}
}
publicclassTestThread1{
publicstaticvoidmain(String[]args){
SubThread1st1=newSubTread1();
st1.setName(“子线程1”);
st1.start();
Thread.currentThread().setName(“主线程”);
for(inti=0;i<10;i++){
System.out.println(Thread.crrentThread().getName()+”:
”+i);
if(i==20){/*当i等于20的时候,当前线程(主线程)停止运行,并运行线
程st1,当st1运行结束,继续运行主线程*/
try{
st1.join();
}catch(InterrupterExceptione){
e.printStackTrace();
}
}
}
}
}
#例子4:
isAlive()
classSubThread1extendsThread{
publicvoiarun(){
for(inti=0;i<10;i++){
System.out.println(Thread.currentThread().getName()+”:
”+i);
}
}
}
publicclassTestThread1{
publicstaticvoidmain(String[]args){
SubThread1st1=newSubTread1();
st1.setName(“子线程1”);
st1.start();
Thread.currentThread().setName(“主线程”);
for(inti=0;i<10;i++){
System.out.println(Thread.crrentThread().getName()+”:
”+i);
if(i==20){/*当i等于20的时候,当前线程(主线程)停止运行,并运行线
程st1,当st1运行结束,继续运行主线程*/
try{
st1.join();
}catch(InterrupterExcptione){
e.printstackTrace();
}
}
}
System.out.println(st1.isAlive());//判断线程st1是否还存活(当前结果是否);
}
}
#例子5:
sleep(longa),需要抛trycatch异常
classSubThread1extendsThread{
publicvoiarun(){
for(inti=0;i<10;i++){
System.out.println(Thread.currentThread().getName()+”:
”+i);
try{
Thread.sleep(1000);//当线程没执行一次for循环睡眠1000毫秒
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
}
}
publicclassTestThread1{
publicstaticvoidmain(String[]args){
SubThread1st1=newSubTread1();
st1.setName(“线程1”);
st2.setName(“线程2”);
st1.start();
st2.start();
}
}
#例子6:
设置优先级
classSubThread1extendsThread{
publicvoiarun(){
for(inti=0;i<10;i++){
System.out.println(Thread.currentThread().getName()+”:
”+i);//调用当前线程的名字,当前线程是st1
}
}
}
publicclassTestThread1{
publicstaticvoidmain(String[]args){
SubThread1st1=newSubTread1();
st1.setPriority(Thread.MAX_PRIORITY);//设置线程st1的优先级为最大,即10
st1.setName(“子线程1”);
st1.start();
Thread.currentThread().setName(“主线程”);
for(inti=0;i<10;i++){
System.out.println(Thread.crrentThread().getName()+”:
”+i);
}
}
}
[2]第二种创建:
实现Runnable接口
classThread2implementsRunnable{//1.创建一个类实现Runnable接口
publicvoidrun(){//2.实现接口的抽象方法run方法
//子线程执行的代码
for(inti=1;i<=100;i++){
System.out.println(Thread.currentThread().getName+”:
”+i);
}
}
}
publicclassTestThread2{
publicstaticvoidmain(String[]args){
Thread2th=newThread2();//3.创建一个Runnable接口的实现类的对象
Threadthread1=newThread(th,”线程1”);/*4.创建一个Thread类的对象,并将Runnable实现类的对象加入到构造器中,
此时创建的Thread对象即为一个线程
*/
Threadthread2=newThread(th,”线程2”);//启动线程;过程:
执行Thread对象生成时构造器形参的对象的run方法
Threadthread3=newThread(th,”线程3”);
thread1.start();//5.调用Thread的start方法,启动线程
thread2.start();
thread3.start();
}
}
(2)线程创建方法之继成和实现的区别
[1]联系:
publicclassThreadimplementsRunnable{}
[2]哪种方式好?
为什么
实现优于继承
原因:
1.避免了java单继承的局限性
2.如果多线程操作同一份资源(不过可能存在一些线程安全问题),更适合使用实现的方式
3.线程安全问题
(1)存在的原因
由于一个线程在操作共享数据的过程中,未完毕的情况下,另外的线程也参与进来,导致共享数据存在了安全问题
(2)如何解决:
-1-解决原理:
必须让一个线程操作完毕共享数据后,其他线程才有机会操作共享数据
-2-java中解决线程安全的方式:
线程同步机制。
(以下两种方法解决)
[1]方法一:
同步代码块
-1-语法格式:
synchronized(同步监视器){(读音:
sing克瑞耐zed)
//需要被同步的代码(即为操作共享数据的代码,这里需要特别注意)
}
-2-使用场景和锁的使用:
^1.共享数据多线程共同操作一个数据(变量)
^2.同步监视器(即锁):
由任意一个类的对象来充当(不过在所有线程中,本对象必须只能
有一个),哪个线程获得此监视器,谁就执行大括号里被同步的代码。
俗称:
锁。
要求所有
线程必须使用同一把锁。
(例子如下)
运行结果如下:
PS:
实现this,继承慎用:
在通过实现Runnable创建线程时,可以用this作为同步监视器,但是通过继承Thread类来创建线程,慎用this(如果创建的类对象只有一个时可以用,不然不可以用)
[2]方法二:
同步方法(例子如下图)
过程:
将操作共享数据的方法声明为synchronized。
此方法为同步方法,能够保证其中一个线程执行此方法时,其他线程在外等待直至此线程执行完此方法。
同步方法的锁是:
当前this。
注意:
不管是同步代码块还是同步方法,synchronized所包含的内容必须是共享数据部分,不能多也不能上,比如上述例子,多了sleep一段代码块运行时就只执行线程1了。
4.线程的生命周期
线程和进程一样分为五个阶段:
创建、就绪、运行、阻塞、终止
补充:
1.wait阻塞,sleep、yield不阻塞:
调用wait方法可以让线程进入阻塞状态。
注意sleep和yield方法不能让线程进入阻塞状态。
//本句看法有疑问
2.线程安全问题总结:
线程在调用run方法运行的时候,当别的线程过来抢占CUP执行权的时候,原来的线程可能程序还未执行完,并进入就绪状态,这就导致了线程安全问题。
5.线程的通信
同步锁
ps:
每个java程序都有一个隐含的主线程:
main方法
和一个垃圾回收线程(守护线程,不会显现出来,但在后台运行)