您的位置:首页 > 职场人生

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

2011-11-29 23:41 239 查看
---------------------- 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培训 、期待与您交流!
----------------------

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息