黑马程序员_多线程技术(线程的创建Thread和Runnble,死锁,线程间通信,join,yield)

来源:互联网 发布:动易cms价格 编辑:程序博客网 时间:2024/05/22 16:00

           ------- android培训java培训、期待与您交流!---------                                                                     

 

多线程技术          

1.多线程概述

(1)进程:正在执行中的程序,比如QQ,javac等

(2)线程:进程中的一个独立控制单元,线程控制着进程的执行。一个进程至少有一个线

(3)多线程的好处:可使程序产生同时运行的效果,多线程下载可提高效率。

2.多线程的两种创建方式:

第一种方式:继承Thread类

创建步骤:

(1)定义一个类继承Thread(那么此类也就变成了Thread类,拥有Start方法。

(2)复写Thread类中的run方法(将需要使用多线程运行的代码存在run方法,让线程运行)

(3)调用线程的start方法.

注意:start():开启一个新线程并运行run方法中的代码,

而调用run方法只是对象调用方法,而不会创建新的线程。


第二种方式:实现Runnable接口。

创建步骤:

(1) 定义类实现Runnable接口

(2)覆盖Runnable接口中的run方法。(还没有拥有线程)

(3)通过Thread创建线程对象。

(4)将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数。

(5)调用Thread类的Start方法开启线程,Runnable接口的run方法即可运行。

3.实现方式和继承方式的区别

(1)继承了一个类不能再继承其他类,java只支持单继承,这样就会出现类继承的局限性。

(2)继承Thread:线程代码存放在Thread类的run方法中,直接就可以调用子类的Start方法即可开启线程。

(3)实现Runnable:线程代码存放在Runnable接口的子类的run方法中,开启线程还需要new Thread();

(4)在定义线程时,建议使用实现方式。

4.线程的状态和获取线程对象以及名称

线程的状态: 1被创建——2运行——3阻塞(临时状态,具备执行资格但没执行)——4冻结———5消亡。

获取都有自己的名称:Thread-编号从0开始

获取对象方法:

static Thread currentThread()获取当前线程对象。getName()获取线程名称。setName()设置线程名称。

5.线程的安全解决

(1)产生安全问题的原因:当多个线程在操作同一个共享数据时,

一个线程还没执行完,另一个线程参与进来,导致共享数据产生了错误。

(2)解决办法:

同步代码块: synchronized(锁对象){需要被同步的代码数据;}

<1>对象如同锁,持有锁的线程才可以在同步中执行。

<2>同步的前提:必须要有两个或两个以上的线程,必须是多个线程使用的同一个锁对象。

同步函数:

非静态同步函数的锁:this

函数需要被对象调用,那么函数都有一个所属对象引用就是this,所以同步函数使用的锁是this.

静态同步函数的锁:class对象

因为静态方法中不可以定义this,所以锁不可能是this。静态进内存时,内存中没有本类对象,

但是一定有该类对应的字节码文件对象,类名.class,该对象的类型是class.

6死锁:同步中钳套同步容易出现死锁现象,应该避免这样现象发生。

class Test implements Runnable{private boolean flag;Test(boolean flag){this.flag = flag;}public void run(){if(flag){while(true){synchronized(MyLock.locka){System.out.println(Thread.currentThread().getName()+"...if locka ");synchronized(MyLock.lockb){System.out.println(Thread.currentThread().getName()+"..if lockb");}}}}else{while(true){synchronized(MyLock.lockb){System.out.println(Thread.currentThread().getName()+"..else lockb");synchronized(MyLock.locka){System.out.println(Thread.currentThread().getName()+".....else locka");}}}}}}class MyLock{static Object locka = new Object();static Object lockb = new Object();}class  DeadLockTest{public static void main(String[] args) {Thread t1 = new Thread(new Test(true));Thread t2 = new Thread(new Test(false));t1.start();t2.start();}}


7.线程间通信

(1)线程间通信:

其实就是多个线程在操作同一个资源,但操作的动作不同。

(2)等待唤醒机制:

<1>wait(),notify(),notifyAll()都使用在同步中,因为只有同步才具有锁,所以要对持有锁的线程操作。

<2>这些用来操作线程的方法为什么定义在Object类中?

a.这些方法存在于同步中。

b.使用这些方法时必须要标识所属的同步的锁。

c.等待和唤醒必须是同一个锁。

d.锁可以是任意对象,所以任意对象调用的方法一定定义在Object中。

(3)wait(),sleep()的区别:

wait():释放资源,释放锁。

sleep():释放资源,不释放锁。

(3)举例:生产者与消费者

<1>对于多个生产者和消费者,为让被唤醒的线程再一次判断标记,故要定义while判断标记。

<2>为什么定义notifyAll?

因为需要唤醒对方线程,只用notify容易出现只唤醒本方线程的情况,导致程序中的所有

线程都等待。

<3>JDK1.5提供的多线程升级解决方案。

将同步synchronized替换成现实Lock操作。将Object中的wait,notify,notifyAll替换成了

condition对象。该对象可以用Lock锁进行获取。

8.停止线程:

(1)stop方法已经过时。

(2)如何停止线程?

只有一种,就是让run方法结束,开启多线程运行,运行代码通常是循环结构。只要控制住循环,

就可以让run方法结束,也就是线程结束。

(3)特殊情况:

<1>当线程处于了冻结状态,就不会读到标记,那么线程就不会结束。

<2>当没有指定的方式让冻结的线程恢复到运行状态时,这时需要对冻结进行清除,强制让线程恢复

到运行状态中来,这样就可以操作标记让线程结束。

(4)Thread类提供该方法:interrupt()

9.守护线程:

setDaemon:

public final void setDaemon(boolean on)

(1)当正在运行的线程都是守护线程时,JVM退出。

(2)该方法必须在启动线程前调用。

(3)主线程是前台线程,前台线程一结束,守护线程自动结束。

10.join方法:

join://抢夺CPU执行权

public final void join()

throws InterruptedException

等待该线程终止

(1)当A线程执行到了B线程的join()方法时,A就会等待,等B线程都执行完,A才会执行。

(2)join可以用来临时加入线程执行。

11.优先级&yield方法

setPriority(int newPriority)

更改线程的优先级(默认是5)

(1) MAX_PRIORITY-->10

NORM_PRIORITY--->5

MIN_PRIORITY--->1

(2)注:在任务管理器的进程中,也可进行优先级设置。

yield:临时停止

public static void yield()

暂停当前正在执行的线程对象,并执行其他线程。yield可稍微减缓线程的运行,

使线程达到接近平均运行的效果。







原创粉丝点击