黑马程序员Java笔记——多线程篇

来源:互联网 发布:软件系统业务流程图 编辑:程序博客网 时间:2024/06/06 23:16

----------- android培训、java培训、java学习型技术博客、期待与您交流! ---------

关键词:多线程的秘密花园:Thread先生与Runnable小姐、同步锁、……

引子:

现实生活中,我们可以同时做很多事情:在写代码的同时可以听音乐;在做饭的同时可以打电话等……。在使用计算机的时候也可以一边听歌,一边玩游戏。那么我们Java是否支持多线程呢,让我们来学习下。


概要:
一,进程和线程

    ① 线程:程序中单独顺序的控制流, 线程本身依靠程序进行运行。线程是程序中顺序控制流,只能使用分配给程序的资源和环境

  

    ② 进程:执行中的程序

    进程是一个执行过程,是一个动态的概念;
    进程是一个持有资源和线程的载体;
    一个进程可以包含一个或多个线程
    一个进程可以至少要包含一个线程

    ③ 单线程
    程序中只存在一个线程,实际上主方法就是一个主线程

    ④ 多线程
    多线程是一个程序中运行多个任务
    多线程的目的是更好的使用CPU资源

二、Thread类和Runnable接口

Thread先生:懂得礼让,绅士风范。每一个男人的梦想都是从一个女孩开始的。实现Runnable接口的线程类。

Thread的常用方法

1,取得当前线程对象currentThread( )

2,取得线程名称:getName( )

3,判断线程是否启动isAlive( )

4,线程强制运行join( )

5,线程休眠sleep( )

6,唤醒线程notify()

7,设置优先级setPriority()

6,线程的礼让yield()


Runnable小姐:娇小
run():使用实现接口Runnable 的对象创建一个线程时,启动该线程将导致在独立执行的线程中调用对象的 run 方法。

三、线程的实现,在Java有两种方法来实现线程:

(1)创建线程的第一种方式:继承Thread ,由子类复写run方法。 

步骤: 

1,定义类继承Thread类; 

2,目的是复写run方法,将要让线程运行的代码都存储到run方法中; 

3,通过创建Thread类的子类对象,创建线程对象; 

4,调用线程的start方法,开启线程,并执行run方法。

(2)创建线程的第二种方式:实现一个接口Runnable

 步骤: 

1,定义类实现Runnable接口。 

2,覆盖接口中的run方法(用于封装线程要运行的代码)。

3,通过Thread类创建线程对象; 

4,将实现了Runnable接口的子类对象作为实际参数传递给Thread类中的构造函数。  

5,调用Thread对象的start方法。开启线程,并运行Runnable接口子类中的run方法。


思考:

(1)为什么要传递Runnble接口子类呢?因为要让线程对象明确要运行的run方法所属的对象。


(2)两种实现多线程的方式对比分析:

推荐:采用方式二

①适合多个相同代码的线程去处理同一个资源的情况,把线程同程序代码,数据有效分离,体现了面向对象的思想
②避免了Java单继承带来的局限性。


(3)线程是启动不是通过run方法来使用的,而是通过start方法

通过调用currentThread( ).getName( )方法来演示
run()方法中封装的就是线程需要执行的任务。
如果在主方法中直接调用run()方法,其实是在主方法中由主线程执行封装的线程任务。

  start()方法是Thread类中开启线程的方法。


四、线程的状态——线程的生老病死

创建状态:准备好了一个多线程对象。

就绪状态:调用了start( )方法,等待CPU进行调度。

运行状态:执行run( )方法,具有执行资格,同时具有执行权。

冻结状态:sleep(time),wait()notify()唤醒;线程释放了执行权,同时释放执行资格。

阻塞状态:具有CPU执行资格,没有执行权。暂时停止执行,可能将资源交给其他线程使用。

终止状态:当Thread对象创建完成时,线程的生命周期就开始了,当run()方法中代码正常执行完毕或者抛出一个未捕获异常或者错误,线程的生命周期便会结束。对Java程序来讲,只要还有一个前台线程在运行,这个程序就不会结束,如果一个线程中只有后台线程在运行,这个线程就会结束。


五、前台线程与后台线程:

新创建的线程默认都是前台线程,如果某一个线程在启动之前调用了setDaemon(true)就变成后台线程了。

注意:要将某个线程设置为后台线程,必须在该线程启动前,否则会引发IllegalThreadStateException异常


六、同步和死锁:

关键字synchronized,同步有两种形式,同步代码块和同步函数。

验证同步代码块与同步函数的锁是否相同,可以采用如下思路:
1,创建两个线程对象,其中线程1使用同步代码块,线程2使用同步函数;

2,两个线程对同一资源进行操作,如果没有出现线程安全问题说明同步函数与同步代码块使用的是同一个对象锁)


同步代码块与同步函数的区别?
同步函数的锁对象是this,同步代码块的锁是任意对象,建议使用同步代码块
静态同步函数的锁不是this是该函数所属对象的字节码文件,可以使用this.getclass( )也可以使用对象.class表示


同步的好处:解决线程的安全问题。

同步的弊端:牺牲了线程执行效率。
同步的前提:多个线程对象一个锁。
单例模式下的多线程,饿汉式下多线程没有影响,
懒汉式下,可以采用同步,来解决线程安全问题,为提高效率使用同步代码块,而不使用同步函数

注意:线程状态:wait()和notify()、以及notifyAll()必须定义在同步中


死锁,

情景1条件矛盾,解锁,一方降低要求即可
情景2同步嵌套

举例:伪代码
大学生(目标月薪过万){
    HR(三年项目经验)

}


七、线程间通信:多个线程在处理同一资源,但是任务却不同。


JAVA1.5后新特性Lock对象:
    将同步和锁封装成了对象,并将操作锁的隐式方式封装到对象,将隐式动作变成了显示动作
Lock接口,替代了同步函数和同步代码块,并将同步锁的隐式操作,变成了显式操作,还可以在同一个锁上添加多组监视器方法。lock()获取锁,unlock()是否锁——通常定义在finally{    }中。
Condition接口,替代了Object中的wait(),notify(),notifyAll()方法。将这些方法进行了单独封装变成了Condition监视器对象可以同任意锁组合。


代码演示:
1,两种实现多线程的方式
2,线程间通信,生产者消费者
3,多线程下的单例
4,同步代码块,同步函数,静态同步代码块、JAVA1.5新特性:Lock对象
5,线程常用方法:join(),sleep(),守护线程,中断线程,线程的停止

0 0
原创粉丝点击