------- android培训、java培训、期待与您交流! ----------
1:多线程
(1)多线程:
进程:正在运行的应用程序
线程:应用程序的最小执行单元,执行路径
单线程:假如一个应用程序只有一条执行路径,被称为单线程程序
多线程:应用程序有多条执行路径
举例:迅雷下载,jvm的启动(main线程和垃圾回收线程)。
(2)多线程的实现方案:
A:继承Thread类
B:实现Runnable接口
调用start()和run()方法的区别?
直接调用run()方法,是一个普通方法
run()调用是一个普通方法的调用,通过线程执行代码的时候,
需要启动线程,并调用run()方法。
而启动线程和调用run()的方法方法是start()
为什么会有第二种方式实现多线程呢?
因为java是单继承的,如果一个类已经有父类了,那么,它就无法再继续继承Thread。
所以,会出现接口的方式。因为一个类继承类的同时还可以实现接口。
示例:
class MeThread extends Thread{
public void run(){ //继承父类多线程接口需要覆写父类方法
for(int i=0;i<100;i++){
System.out.println(getName()+"**"+i);//继承父类的getName()方法,可以调用省略了this.
//可以写成System.out.println(Thread.currentThread().getName());
//currentThread()静态方法,返回当前引用对象,可以直接使用类名调用
}
}
}
public classThreadDemo {
public staticvoidmain(String[] args) {
MeThreadm=newMeThread();
m.start();//调用多线程执行方法
for(inti=0;i<100;i++){
System.out.println("-----"+i);
//可以看出是多线程,在main线程方法向下执行时,遇到了start()启动了另一个线程,此时start()开始执行
//而main继续向下执行,两个线程并列执行,开始争夺虚拟机资源
}
}
}
(3)线程随机性原理
应用程序是在CPU的高效切换间运行。
(4)线程的生命周期
A:新建新建了线程对象
B:就绪具备执行资格,不具备执行权
C:运行具备执行资格,具备执行权
阻塞 -- 就绪
不具备执行资格,不具备执行权
D:死亡线程对象变成垃圾
线程状态图解
(5)卖票案例通过两种方式实现。
示例:
Thread实现方式
/*
* 多线程的应用:多个窗口同时买票的应用
* */
package ThreadTicket;
class Tickets extends Thread{
privatestaticinttickets=100;//之所以设置为静态,是因为
// 每新建一个线程对象,就会有100张票,因此设置为静态共享变量,几个卖票窗口共享这些票
publicvoidrun(){
while(true){
if(tickets>0){
System.out.println(getName()+"正在卖第"+tickets--+"张票");
}else{
break;
}
}
}
publicTickets(String name){
super(name);
//建立构造方法,在子类构造方法里面调用父类给名字赋值的构造方法this.name=name;
}
}
public classTicketsDemo{
public static void main(String [] args){
Ticketst=newTickets("1号窗口");
Ticketst1=newTickets("2号窗口");
Ticketst2=newTickets("3号窗口");
Ticketst3=newTickets("4号窗口");
t.start();
t1.start();
t2.start();
t3.start();
}
}
Runnable实现方式
示例:
/*
* 第二种实现多线程的方法:实现Runnable接口
这个接口的出现避免了java只能单继承的局限性
* */
package RunnableTicket;
/*
* 使用Runnable接口实现多线程卖票
* */
class Tickets implements Runnable{
private int tickets=100;
public void run(){
while(true){
for(int i=0;i<100;i++){
//此系统可能出现安全问题,若此时剩了1张票,t1进来走过if语句还未到输出语句,t2此刻抢到了cpu此时票数
//还是大于0,同理t3,t4可能会进来,那么出现的问题是可能会卖出0,-1,-2张票
if(tickets>0){
System.out.println(Thread.currentThread().getName()+"正在卖第"+tickets--+"张票");//因为currentThread()是静态方法,可以直接调用,因为返回的是一个对象,可以直接调用其方法
}else{
break;
}
}
}
}
}
public classTicketsDemo {
public static void main(String [] args){
Tickets t=new Tickets();
/* m.start(),因为start()是Thread的方法,MyRunnable和
Thread没有联系,所以不可以使用.
在Thread的构造方法中有Thread(Runnabletarget) 和Thread(Runnabletarget, String name)
第二个在产生新线程对象的同时可以赋名字
此方法接收Runnable对象可以产生新的线程对象
所以可以通过建立Thread对象,来调用次方法产生新的线程对象
*/
Thread t1=newThread(t,"1号窗口");
Thread t2=newThread(t,"2号窗口");
Thread t3=newThread(t,"3号窗口");
Thread t4=newThread(t,"4号窗口");
t1.start();
t2.start();
t3.start();
t4.start();
}
}
(6)卖票出问题了?线程安全问题?
A:线程访问的随机性
B:线程访问的延迟
(7)解决方案:同步
1)使用synchronized代码块及其原理
public void output(String name){
synchronized (this) {
for (int i = 0; i < name.length(); i++) {
System.out.print(name.charAt(i)+" ");
}
System.out.println();
}
}
2)使用synchronized方法
class OutPuter{
public synchronizedvoid output(String name){
for (int i = 0; i < name.length(); i++) {
System.out.print(name.charAt(i)+" ");
}
System.out.println();
}
}
锁对象是谁呢?
a:同步代码块是任意对象
b:普通同步方法是this对象
c:静态同步方法是当前类的字节码文件对象
同步的好处:解决数据安全问题
同步的弊端:效率低
假如针对代码你加了同步,发现还是没有解决问题?
A:是不是对所有涉及到的内容都加了锁
B:考虑所有的锁对象是不是同一把
(8)如何判定程序是否会有线程安全问题?
A:程序被多个线程访问
B:有共享数据
C:共享数据被多条语句操作
(9)单例模式中的线程安全问题
懒汉式的单例模式:可能会出现安全问题
当一个对象进入判断语句还未进入new对象时另一个对象可能也进入,
然后就会new两个对象,造成安全问题
因此需要同步锁机制
如图
/*class Single {
privatestatic Single s=null;
privateSingle(){}
publicstatic Single getInstance()
{
if(s==null){
returns=new Single();
}
returns;
}
}会产生安全问题
*/
//加同步锁之后
class Single{
privatestatic Single s=null;
privateSingle(){}//外界无法创建对象
publicstatic synchronized Single getInstance(){ //因为方法是静态的,此时同步锁的对象是字节码对象 Single.class
if(s==null){
s=newSingle();
}
returns;
}
}
public class SingleDemo {
publicstatic void main(String[] args) {
Single s=Single. getInstance();
}
}