读书人

多线程(2)

发布时间: 2012-06-28 15:20:04 作者: rapoo

多线程(二)

自己设计多线程程序

???? 如何设计使用线程呢?思考:线程是运行在进程上的,要使用线程必须先需要进程。进程是由windows系统分配给应用程序的。所以只要我们写的程序有入口,都是应用程序。通过查看api实现多线程有两种方法,现在我们首先了解第一种实现多线程的方法。

???? 继承Thread类并实现run方法,就可以实现多线程。

???? 怎么样启动一个线程呢?

??? 线程的启动需要手动的调用线程对象的start方法进程开启线程。

?? 开启线程的start方法中有两个作用1.启动线程? 2.执行run方法

?? 线程的运行和进程一样。通常我们说所的线程之间会抢夺cpu资源,同过观察运行例子程序确实是这样的,但是实际上是分给cpu进程的cpu根据线程执行的优先权进程执行线程的。同一个时间,只有一个线程运行,不能多个线程并发的运行。

?? 我们写一个java应用,通过main入口的就是主线程,在主线程中我们可以开启子线程。主线程和子线程是快速交替的在进程中运行的。

?

病毒类的程序:一直抢先执行自己的线程,不允许其他程序抢占cpu资源。这个是病毒程序的设计的思路。

?

思考:为什么我们要覆盖run方法呢

???????? 因为我们要在run方法中书写我们要执行的程序。父类thread 的run方法中为空的方法。

思考: Thread t? = new Thread(); t.star(); 这样能否开启线程

??????? 这样能开启线程,同过start启动线程和执行线程的run方法是空的,这样的线程毫无意义

思考:我们用继承了线程的对象? t? 直接调用run方法和start方法有什么却别

??????? 直接调用t.run 方法,对我们来说跟调用普通方法的run方法是一样的,并没有执行线程。当一个程序执行到t.run方法的时候,只有执行完run方法才会执行下面的程序,这个执行是在主线程中,不会和主线程交替执行。调用run方法开启了线程。就会和主线程进行交替的执行。

?

?

线程的状态:

临时状态

?

???? 临时状态是有执行权,但是cpu暂时没有分配其执行。需要等待某个时刻由cpu分配了执行全,此线程就可以执行。

?

冻结状态:

????? 当线程调用sleep或wait方法的时候,线程主动放弃执行权。这时线程处于冻结状态。通知并告诉cpu这段时间不执行任何操作,所以cpu不会给其分配执行权。

???? sleep 是睡眠多少秒后自动醒来,不需要别人叫醒。

???? wait是等待 ,别人让你等待,并没说等待多长事件。别人用notify可以让你继续执行,不再等待。

?

?

运行状态

?

?? 正在执行的线程。

?

死亡状态

? 当线程执行完,自动消亡。或调用stop方法消亡线程。

?

--------------------

可以获取和设置线程的名称。线程有默认的名称 是从0开始的。

Thread.currrent().getName 就可以获得线程的名称 也可以通过this方法获得线程的名称

Thread的构造方法中有一个含有参数的构造方法就是线程的名称? 也可以通过setName方法设置线程的名称

---------------------

多线程买票

?

开启多线程卖100张票 就能产生一张票被多个线程卖

所以? 把100张票设置成静态的 就可以解决问题。

但是控制台打印票的顺序到最后是132的原因是由双核cpu造成的

?

?

一个线程对象被多次启用,就会抛出线程非法异常。

跟运动员起跑类似,起跑时裁判员开枪,跑了一会又开枪,运动员不是疯了

----------------------------

实现多线程的第二种方式? 实现Runnable 接口

?

?

实现过程:

1.实现Runnable接口

2.实现run方法

3.创建Thread类的对象

4.Thread的构造方法中可以接收一个Runnable对象的参数

5.启动线程? thread对象.start

这时启动的不是Thread类中的空线程导入Run方法,而是实现了Runnable接口的run方法。

?

?

实现Runable接口和继承Thread的区别

1.java是单继承

2.run 方法所属不一样

runnable接口的好处。可以在使用线程的同时又能继承其他的类

----------------------------------

多线程的安全问题

?

比如卖票系统:当买到第0号票的时候? 一个线程进了买票循环 没等到票数见一? 另一个线程又进到了卖票循环 这样打票系统就会打出一张为0号的票? 这是不符合实际的!

?

?

解决方法:一个线程卖完票后另一个线程才能执行其买票功能

     这里就可以用到同步代码块 synchronized(这个里面接受任意对象){

        需要同步的代码快

     }

-----------------------------------

同步:好处? 可以解决线程安全问题

??????? 不足: 线程每次执行的时候要判断是否锁旗标可以进入代码块

??使用地方: 1.必须要有两个以上线程

?????????????????? 2.必须是共享的代码块

---------------------------------------

线程开启后 不一定马上执行

使用同步线程的时候注意是否用的锁旗标是一样的

静态同步方法的锁旗标不是this而是改类的字节码? A.class

?

?

?

单例有两种方式可以实现单例

1.饿汉模式

?

public class A{

???? private static fianl A a = new A();

???? private A(){}

???? private static A? getAInstance(){

??????????????? return a;

???? }

?

}

饿汉模式不会导致多线程的安全问题

2.懒汉模式

public class A{

????? private static A a = null;

???? private A(){

????}

??? public static A getAInstance(){

??????????????if(a==null){

????????? ??????? a = new A();

??? ????????? }else

??????????????? return a;

?

??? }

?

}

分析:当开启两个线程1,和线程2.有中可能是线程1和线程2同时调用getAInstance 方法。

当线程1进了if方法后线程2也进了if方法,并不通事件都执行了 new A()所以在此可见单例被实例化了多次。导致安全问题发送。

解决方法:可以使用同步函数解决问题。但是同步函数有一定的缺陷。每次调用getAInstance的时候都要判断是否cpu把锁释放给改线程。

使用同步代买块和if嵌套可以解决问题,并切效率相对来说比较高。

?

if(a ==null){

? synchronized(obj){

??? a? = new A();

???? return a;

?

}

?

}else{

? return a;

}

?

经过代码的修改如上。只有当a为null的时候进入if代码块。判断是否拥有锁的权限。

?

------------------------------------

同步死锁的问题

如果有两个线程。进入a代码块 需要b代码块的锁。进入b代码块需要a代码块的锁。如果a.b两个锁不相互谦让。就出现死锁问题。

?

synchronized(a){

?

??????????

???????? synchronized(b){

???????

?

????????? }

}

synchronized(b){

???????

?????????

??????????? synchronized(a){

???????

?

?????????????? }

}

?

上图为模型

?

?

?

读书人网 >移动开发

热点推荐