JAVA基础---多线程

一、多线程概述

要理解多线程,就得先理解线程,要理解线程,就得先理解进程,
进程就是Java中正在执行的程序,每个程序都有一个执行顺序,该顺序是一个执行路径,或者叫一个控制单元。
线程就是Java中一个独立的控制单元,线程在控制着进程的执行,只要有一个线程执行,进程就不会结束。
一个进程中至少有一个线程。
多线程:当Java程序中除了有主线程外还有其他自定义的线程时,两种线程同时执行,像这样一个进程中多个线程同时执行,就为多线程。
多线程的好处:多线程的出现能使程序产生同时运行的效果,可以提高程序的执行效率。
计算机cpu的运行原理:我们的电脑上有好多的程序在同时运行,表面上看好像cpu在同时处理这些程序,实际上单核cpu在某一个时刻只能运行一个程序,而我们看到同时运行的效果,实际是cpu在多个进程间做着快速的切换。 而且cpu会执行哪个程序是毫无规律的,这也是多线程的一个特性-随机性。

二、线程的创建方式

Java中创建线程有两种方式:继承方式和实现方式。
1,、继承方式
这种方式是通过继承Thread类,然后覆盖其中的run方法。
步骤:
a、定义类继承Thread类。
b、复写Thread类中的run方法。
目的:将自定义的代码存储在run方法中,让线程运行。
c、创建定义类的实例对象,相当于创建一个线程。
d、用该对象调用start方法,启动线程,并自动调用run方法。
注:如果对象直接调用run方法,相当于没有启动线程,也就是说只有一个线程在运行。
覆盖run方法的原因:
Thread类用于描述线程,该类就定义了一个功能,用于存储线程要执行的代码。该存储功能就是run方法,也就是说Thread类中的run方法,用于存储线程要执行的代码。
程序演示:

2、实现方式
使用继承方式有一个弊端,就是如果改类本来就继承了其他父类,那么就无法通过继承Thread类来创建线程了,这样就有了第二种创建线程方式,实现Runnable接口,复写其中的run方法。
步骤
a、定义类实现接口Runnable。
b、复写Runnable接口中的run方法,目的是为了将要线程执行的代码放入该run方法中。
c、通过Thread类创建线程对象。
d、创建Runnable接口的子类对象,并将该子类对象作为实际参数传递给Thread类的构造函数中。
因为自定义的run方法所属的对象是Runnable接口的子类对象,所以要让线程去指定对象的run方法,就必须明确该run方法所属的对象。
e、调用Thread中的start方法启动线程。
实现方式的好处:避免了单继承的局限性。
程序演示:

三、两种方式的区别和线程的几种状态

1、两种创建方式的区别
继承Thread类线程代码存放在Thread类的子类的run方法中。
实现Runnalbe线程代码存放在接口子类的run方法中。
2、线程的几种状态
被创建:等待启动,调用start启动。
运行状态:具有执行资格和执行权。
临时状态(阻塞):有执行资格,但没有执行权。
冻结状态:遇到sleep方法,和wait方法时,失去执行资格和执行权,sleep方法时间到时,变为临时状态。wait方法到调用notify方法时,变为临时状态。
消亡状态:stop方法,或者run方法结束。

四、线程间的安全问题

1、导致线程出现安全问题的原因
当多语句操作同以线程的共享数据时,一个线程对多条语句只执行了一部分,还没有全部执行完,另外一个线程参与进来,导致共享数据错误。
简单的来说:线程的随机性,多个线程访问出现延迟。
2、解决办法——同步
对多条操作共享数据的语句,只能让一个线程都执行完,在执行过程中,其他线程不可以参与。
在Java中对于多线程的安全问题提供了专业的解决方案——synchronized(同步)
这里也有两种解决方式:同步代码块,同步函数
a、同步代码块
格式:
synchronized(对象)
{
需要被同步的代码块
}
同步可以解决安全问题的根本原因就在那个对象上,其中对象如同锁,持有锁的线程可以在同步中执行,没有持有锁的线程即使获得了cpu执行权也进不去,因为没有锁。
程序:

b、同步函数
格式:
在函数上加上synchronized修饰符即可。
同步函数用的锁是this,函数需要被对象调用,那么函数都有一个所属对象的引用,就是this。
3、同步的前提
a、必须有两个或两个以上的线程
b、必须多个线程使用同一个锁
4、同步的利弊
好处;解决了多线程的安全问题
弊端:多个线程需要判断锁,耗费资源
5、如何寻找多线程中的安全问题
a、明确哪些代码块是多线程运行代码
b、明确共享数据
c、明确多线程运行代码中哪些是操作共享数据的

五、静态函数的同步方式

通过验证发现静态同步函数所使用的锁是该方法所在类的字节码文件对象。类名.class
经典示例:加同步的单例设计模式

六、死锁

当同步中嵌套同步时,就有可能出现死锁
示例:


结果:程序卡主,不能执行。

七、线程间通信

其实就是多个线程操作同一个资源,但是操作动作不同。
程序:


几个小问题:
a、wait(),notify(),notifyAll(),用来操作线程为什么定义在了Object类中?
这些方法存在同步中,使用这些方法时必须标识所属所属的同步的锁,同一个锁上的wait线程,只有被同一个锁上的notiy唤醒,锁可以是任意对象,所以定义在Object类中。
b、wait(),sleep()的区别
wait释放cpu执行权,释放锁,
sleep释放cpu执行权,但不释放锁。
c、为什么要定义notifyAll()
因为在需要唤醒对方线程时,如果只用notify(),容易出现只唤醒本方的情况,导致程序中的所有线程都等待。
2、JDK1.5中提供了多线程升级解决方案。
示例:




八、停止线程

在JDK1.5版本之前,有stop()停止线程的方法。但升级之后此方法已经过时。
那么按照理论来说现在我们只有一种方法能停止线程那就是让run方法结束。
1、开启多线程运行,运行代码通常是循环结构,只要控制住循环,就可以让run方法结束,也就可以让线程结束。
可以在run方法设置一个flag标记,在主线程或者其他线程中,在该线程执行一段时间后,将标志置为false使循环条件不满足。就能结束。
2、   当没有指定的方式让冻结的线程恢复到运行状态时,这时需要对冻结进行清除。强制让线程恢复到运行状态中来。这样就可以操作标记让线程结束。Thread类提供该方法interrupt();


九、什么时候写多线程

当某些代码需要同时被执行时,就用单独的线程进行封装。
示例:

扩展小知识:

1join方法

        当A线程执行到了b线程的.join()方法时,A线程就会等待,等B线程都执行完,A线程才会执行。(此时B和其他线程交替运行。)join可以用来临时加入线程执行。

2setPriority()方法用来设置优先级

        MAX_PRIORITY 最高优先级10

        MIN_PRIORITY   最低优先级1

        NORM_PRIORITY 分配给线程的默认优先级

3yield()方法可以暂停当前线程,让其他线程执行。











  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值