【 多线程 】
主线程:执行主方法的线程,就叫做主线程.
单线程:程序从main开始从上到下一次运行.
程序从main方法开始运行,JVM运行main方法,会找操作系统开辟一个通往cpu的执行路径,cpu可以通过这条路径来执行main方法
这条路径有一个名字叫主线程(main).
●创建线程方式一继承Thread类
实现步骤:
1.创建Thread类的子类
2.重写Thread类中的 run 方法,设置线程的任务
3.创建Thread类的子类对象
4.调用Thread类中的 start 方法开启一个新的线程,执行run方法
是该线程开始执行;Java虚拟机调用该线程的run方法.
结果是两个线程并发第运行;当前线程(main线程)和另一个线程(执行run方法的线程).
多次启动一个线程是非法的.特别是当线程已经结束执行后,不能在重新启动.
打印的结果是随机性的:
开启两个线程,对于cpu来讲就有选择权利
●创建线程方式一实现Runnable接口
实现步骤:
1.创建Runnable接口的实现类
2.重写Runnable接口中的 run 方法,设置线程任务
3.创建unnable接口的实现类对象
4.创建Thread类对象,构造方法中传入Runable接口的实现类
Thread(Runnable target) 分配新的Thread对象
5.调用Thread类中的方法 start , 开启线程执行run方法.
实现Runnable接口的好处:
1.避免了类继承Thread类之后,无法继承其他的类(单继承的局限性)
2.把设置线程任务,和开启线程进行解耦,增强了扩展性
实现类的作用:就是设置线程任务.
Thread类的作用:开启线程
好处:传递不同的实现类,实现类重写的方法不一样,可以调用不同的方法
●线程的匿名内部类使用
匿名:没有名字
内部类:写在其他类内部的类(成员位置:成员内部类,局部位置(方法中):局部内部类)
匿名内部类的格式:
new 父类/接口(){
重写父类/接口中的方法;
}
获取线程的名称:
1.Thread类中的方法getName
返回值:String getName() 返回该线程的名称
2.Thread类中的静态方法,获取当前正在执行的线程
返回值:String Therad currentThread() 返回当前正在执行的线程对象的引用.
设置线程的名称:
1.Thread类中的方法setName(String name)
返回值:void setName(String name) 改变线程名称,使之与参数name相同.
2.子类添加带参数构造,调用父类Thread来的带参构造方法,传递线程的名称,让父类给线程起名字(让父亲给儿子起名字)
Thread(String name) 分配新的Threa对象
Thread类中的sleep方法:
静态方法 没有返回值 sleep(long millis)
在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),休眠结束程序继续执行.
子父类之间的异常:
父类怎么处理异常,子类就怎么处理异常
父类方法没有抛出异常,子类重写方法的时候也不能抛出异常.
【线程安全】
程序出现了线程安全问题
解决方案:
第一种方式:可以使用同步代码块
◆锁对象 可以new一个Object对象 或者this.Thread
synchronized(锁对象){
产生安全问题的代码;
或者是访问了共享数据的代码;
}
★注意:必须要保证多个线程使用的是同一个锁对象
解决方案:
第二种方式:同步方法
使用步骤:
1.把可能出现安全问题的代码抽取到一个方法中
2.把方法增加一个关键字 synchronized
修饰符 synchronized 返回值类型 方法名(参数){
可能出现安全问题的代码;
访问了共享数据的代码;
}
■同步方法使用的锁对象是什么?
使用的就是本类对象 new RunnableImpl()--->叫this
■静态的同步方法,使用什么锁对象?
使用的是本类对象的class属性(反射)
RunnableImpl,clas
解决方案:
第三种方式:使用Lock接口,JDK1.5之后出现的新特性
java.util.concurrent.locks.lock接口
方法:
void lock() 获取锁.
void unlock() 释放锁.
接口的实现步骤:ReentrantLock
实现步骤:
1.在成员位置创建一个Lock接口的实现类对象ReentrantLock
2.在可能出现线程安全问题的代码前,调用lock方法获取锁
3.在可能出现线程安全问题的代码后,调用unlock方法释放锁