黑马程序员-----多线程学习日志

---------------------- android培训java培训 、期待与您交流! ----------------------

 

 

 

多线程概述


1、进程:当前正在执行的程序,代表一个应用程序在内存中的执行区域
2、线程:是进程中的一个执行控制单元,执行路径。
3、一个进程中至少有一个线程在负责控制程序的执行。
一个进程中如果只有一个执行路径,这个程序成为单线程。
一个进程中如果只有多个执行路径,这个程序成为多线程。

Jvm启动其实就是多线程程序,其中有一个程序负责从主函数开始执行,并控制程序流程。
同时为了提高效率,还启动了另一个控制单元,专门负责堆内存中的垃圾回收。
负责执行正常代码的线程,称为主线程。该线程执行的代码都存放在主函数中。
负责收垃圾代码执行的线程,称为垃圾回收线程。该线程要执行代码的finalize中。

 

创建线程


创建新执行线程有两种方法:
方式一:继承Thread类
1、将类声明为Thread的子类,
2、覆盖run方法,
3、创建Thread子类的对象(也就是创建一个线程对象)
4、用start方法启动线程。
 为什么要继承?为什么要覆盖run?
 其实直接建立Thread类对象即可,并开启线程执行就可以了。
 但是虽然线程执行了,可是执行的代码是该线程默认的代码,该代码就存放在run方法中。
 可是定义多线程的目的,是执行自定义的代码,而进程的执行代码都在run方法中,所以要
 将run方法覆盖,将自定义代码写入run方法中,这样线程启动后就将执行run方法中的自定义代码。
 主线程运行的代码都在main函数中,自定义线程的代码在线程对象的run方法中。

方式二:实现Runnable接口
 Runnable 接口:应该由那些打算通过某一线程执行其实例的类来实现
1、定义类实现Runnable接口;class Object implements Runnalbe,
2、并覆写run()方法
3、建立Runnalbe的子类对象;Object object  = new Object();
利用以下构造方法创建Thread类对象:Thread(Runnable object) 创建新的 Thread 对象。
4、start方法启动线程。

两种方式总结:
继承Thread类的方法,会导致每一个线程对象中都存储一份属性数据,无法在多个线程对象中共享公有的数据。
如果将这个公有的数据加上static,虽然实现了共享,但是生命周期过长,有异常以为Thread不可以被多继承。
实现Runnable接口的方法,可以解决以上问题。因为该方式定义了一个可以被多个Thread线程对象共享的Runnable子类对象,这个子类对象中,不但有需要共享的数据,还有需要执行的自定义的方法run();

 

线程的运行状态


1、被创建
2、运行:线程获得执行资格,并已经争夺cpu的使用权,cpu正在处理该线程的代码,此为运行状态。
3、冻结:线程释放了执行资格及cpu的使用权。
4、临时阻塞:线程被创建并start()后,拥有执行资格,但还未争夺到cpu的使用权,这种状态叫临时阻塞
5、消亡:run()中代码运行结束或者stop()后。

线程安全解决方案------同步
解决方法:同步
同步格式:
 1、同步代码块:
 synchronized(对象) //就像一把锁,为任意对象,通常设定为是this,或者创建个对象object
{   确定需要同步的代码 }
2、同步函数:
public synchronized void add() {} //同步函数的锁是this
 区别:同步代码块用的锁可以是任意对象,同步函数的锁只能用this,一般来说,用同步代码块比较好

同步原理:
 通过一个对象锁,将多条操作共享数据的代码进行了封装并加锁。
 只有持有这个锁的线程才有机会进入同步中的去执行,在执行期间,即使其他线程获取到执行权,
 因为没有获取到锁,所以只能在外面等。只有同步中的线程执行完同步代码块中的代码。
 出同步代码时,才会释放这个锁,那么其他程序线程才有机会去获取这个锁,并只能有一个获取到而且进入到同步中。
锁机制最好的体现:火车上的卫生间。
同步前提:
1、 必须两个或两个以上的线程
2、 必须要保证使用同一把锁

验证静态同步函数到底用的是哪个锁?
静态同步函数使用的锁肯定不是this,
因为静态函数中先于对象的this。
静态随着类的加载而加载,这时有可能内存还没有该类对象,此时的锁的对象是类的Class所表示的字节码对应的对象。


等待/唤醒机制
通常用在同步中,需要锁的支持,用锁调用。锁.wait(),锁.notify()
使用方法:
wait(), 让线程等待,将线程存储到一个线程池中(一个锁对应一个线程池)。
notify() 唤醒被等待的线程,通常唤醒线程池中的第一个,被唤醒的线程处于临时阻塞状态
notifyAll() 唤醒所有被等待的线程,
这三个方法都用来操作线程,大多都定义在object中,因为这三个方法使用时都需要定义在同步中,要明确这些方法所操作的线程所属的锁。简单说,就是在A锁中被wait的线程,只能被A锁的notify方法唤醒,所以一定要标清楚wait,notify方法所属的锁对象,而锁对象可以是任意对象。sleep():释放执行权,不释放锁,虽不执行但仍占用资源,直到sleep过后才会释放锁。wait():释放执行权,释放锁,只有释放锁后才能被唤醒,不然其他线程一直等待,进程死去。

死锁

在同步代码块的循环嵌套中容易发生多线程锁等待,最后形成死锁。严重阻碍代码的运行,在设计中应避免死锁的发生。为避免死锁和多线程正常,引入接口Lock,它是控制多个线程对共享资源进行访问的工具,Lock的实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作。此实现允许更灵活的结构,可以具有差别很大的属性,可以支持多个相关的 Condition对象。

 

 

 

 

---------------------- android培训java培训 、期待与您交流! ----------------------

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值