首先 创建线程的方式有两种:实现Runnable接口,或者继承Thread类继承方式:
1、继承Thread类步骤 重写父类中的Run方法
2、建立子类对象的同时线程也将被创建
3、通过调用start方法开启线程
实现方式:
1 定义类实现Runnable接口
2 覆盖Runnable接口中的run方法
run方法用于存放该线程要运行的代码
3 通过Thread类建立线程对象
4 将Runnable接口中的子类对象作为实际参数传入给Thread类的构造函数
为什么要将Runnable接口中的子类对象传入呢 ?
因为自定义的run方法是属于Runnable接口中的子类对象,所以要让线程执行制定对象的run方法就必须明确该run方法所属的对象
5 调用Thread类的start方法开启线程 并调用Runnable接口里的Run方法
实现方式和继承方式的区别
实现方式的好处 :避免的单继承的局限性。
在定义线程实,建议使用实现方式
两种方式的区别:
继承Thread:线程代码存放在Thread子类的run方法中
实现Runnable:线程代码存放在接口的子类的run方法中
线程的生命周期:
被创建
运行
冻结 当一个线程被sleep或者wait方法调用 放弃了执行资格
阻塞 具备执行资格,但是没有执行权
销毁 线程代码运行结束后
线程的安全问题
原因:当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分还没有执行完,另一个线程参与进来。导致了共享数据的错误
解决方法:对多条操作共享数据的语句,只能让一个线程执行完在执行过程中,其他线程不可以参与执行
JAVA对于多线程的安全问题提供了专业的解决方式。有两种表现形式
1同步代码块
synchronized(对象){
需要被同步的代码
}
对象如同锁,持有锁的线程可以再同步中执行,没有持有锁的线程即使获取了CPU执行权也进不去。因为没有锁
同步的前提 1必须同时拥有两个或者以上的线程 2必须使用同一个锁 必须保证同步中只能有一个线程在运行。 好处:解决了多线程的安全问题 弊端:多个线程都需要判断锁,较为消耗资源 2同步函数 函数需要被对象调用。那么函数都有一个所属对象的引用。就是this。 所以同步函数使用的锁是this。 如果同步函数被静态修饰后,使用的锁不是this.因为静态方法中也不可以定义this。 静态进内存时,内存中没有本类对象。但是一定有该类的字节码文件对象。类名.class 该对象的类型是Class 静态的同步方法,使用的锁是该方法所在的类的字节码文件对象。 类名.class 死锁 同步中嵌套同步将有可能会发生死锁 程序中要避免死锁 线程间通信 其实就是多个线程在操作同一个资源,但是操作的动作不同 等待唤醒机制 wait(); notify(); notifyAll(); 这样的方法都使用在同步中,因为要对持有监视器(锁)的线程操作。所以要使用在同步中因为只有同步在具有锁。
为什么这些操作线程的方法要定义在Object类中呢。因为 这些方法在操作同步中线程时,都必须要表示他们所操作的线程的持有的锁,只有同一个锁上的被等待线程可以同一个锁上的nitify唤醒。
不可以对不同的锁中的线程进行唤醒。
也就是说,等待和唤醒必须是同一个锁。
而锁可以是任意对象,所以可以被任意对象调用的方法被定义在Object中。
JDK1.5中提供了多线程升级解决方法 将synchronized替换成显示的Lock操作 将Object中的wait,,notfiy,notifyAll替换了Condedition对象 该对象可以Lock锁获取进行获取。 线程销毁 stop方法已经过时 如何停止线程? 只有一种方式,run方法结束 开启多线程程序运行代码通常是循环结构只要控制住循环就可以让run方法结束,从而让线程结束 特殊情况: 当线程处于冻结状态,就不会读取到标记。那么线程就不会结束。 当没有指定的方式让冻结的线程恢复到运行状态时,这时就需要对冻结状态进行清除,强制让线程恢复到运行中来。这样就可以操作标记让线程结束。Thread类中提供了该方法 interrupt方法 守护线程:有setDeamon方法 如果前台线程停止 则守护线程也停止 Join方法 当A线程执行到了B线程的join方法时,那么A线程就会等待B线程都执行完A才会执行 join可以用来零时加入线程执行 线程优先级 使用setPriority方法设置优先级,默认优先级是5 1、5、10是最明显的优先级所以起名为max——Priority,min——Priority,Norm——Priority。 yieId方法:暂停当前正在执行的线程对象,并执行其他线程
|