您的位置:首页 > 职场人生

黑马程序员--多线程概述和常见问题

2014-06-19 20:22 351 查看
------- <a href="http://www.itheima.com" target="blank">android培训</a>、<a href="http://www.itheima.com" target="blank">java培训</a>、期待与您交流! ----------

谈到线程,不得不先要理解什么是进程。进程是一个正在执行中的程序。每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者叫做一个控制单元。线程(Thread)就是进程中的一个独立的控制单元,线程在控制着进程的执行。一个进程中至少有一个线程,即至少有一个控制单元。

Java虚拟机启动时会有一个进程java.exe,该进程中至少一个线程负责java程序的执行, 而且该线程称之为主线程。需要强调的是JVM在启动时不止有一个进程,还有负责

垃圾回收机制的线程。

如何在自定义的代码中,自定义一个线程 呢?线程存在于某一个进程当中,进程是系统创建的,所以Java中已经提供了此类事物的体现,java.lang包中有一个Thread类。

创建线程的一种方式就是:

1. 定义类继承Thread类

2. 重写(覆盖)Thread中的run( )方法。目的是:将自定义的代码存储在run方法中,让线程运行

3. 调用线程的start( )方法。 该方法有两个作用:启动线程,调用run()方法

示例代码1:

package com.itheima.day11;

class Demoextends Thread{

public void run(){

for (int x = 0; x < 500; x++) {

System.out.println("demo run---"+x);

}

}

}

public class ThreadDemo {

public static void main(String[] args) {

//继承完之后,创建对象,即创建好了一个线程

Demo d =
new Demo();

//开启线程并执行该线程的run()方法,start是调用的底层,让控制台执行的动作

d.run();

for (intx = 0; x < 500; x++) {

System.out.println("Hello World!--"+x);

}

}

}

发现:

每一次的运行结果都不同,因为多个线程都在获取CPU的执行权,CPU执行到哪个进程的线程,就会执行哪一个进程

明确一点:在某一时刻,只能有一个程序在运行(多核除外)

原理:

CPU在做着快速的切换,以达到看上去同时运行的效果

这就是多线程的一个特性:随机性(哪个程序抢到CPU资源,它就会执行,执行多长时间,由CPU决定)

事实:

Windows本身是一个多任务操作系统,表面看似在同时执行多个程序,其实,CPU在某一个时间内只能执行一个程序,它是在多个程序之间进行快速的切换,速度非常之快,所以会认为是同时执行,其实是在切换每一个进程中的线程,若一个进程中有多个线程,CPU也在进行切换,这就是为什么同一时间内开的程序越多,电脑就会运行的

越慢(多个线程在抢夺CPU资源,但是是有CPU决定的),但是若为双核,多核,就能够实现同时执行,双核多核

以后内存就是 瓶颈,临时存储空间要足够大,双核标配内存要在2G以上

run( )和start( )的特点

Thread类用于描述线程,该类定义了一个功能,即run()方法,用于存储线程要运行的代码。

主线程运行的代码,存储在main()方法中,这是由JVM定义的,这就是虚拟机调用main()方法的原因

因为是主线程在调用.Java中规定了自定义的线程的代码,存储在Thread的run()方法中 start()调用的是 Thread类

所属对象的run()方法,要沿袭父类功能,重写父类内容

调用start()和run() 的不同

A. d.start();--->开启线程并执行该线程的run()方法,start是调用的底层,让控制台执行的动作.打印结果是

交替打印

B. d.run();---->仅仅是对象调用方法,而线程创建了,并没有执行.(仅仅是封装了线程要运行的代码).打印结果是

先将run中封装的代码执行完之后再执行start的代码,没有启动主线程

创建线程的第二种方式:实现Runnable接口

步骤:

1. 定义类实现Runnable

2. 覆盖Runnable接口中的run()方法

3. 通过 Thread类创建线程对象

4. 将Runnable接口的子类对象传递给Thread类的构造函数

为什么要将Runnable接口的子类对象传递给Thread的构造函数呢?

因为,自定义的run()方法所属的对象是Runnable接口的子类对象

所以要让线程指定对象的run()方法,就必须明确该run方法所属对象

5. 调用Thread类的start()方法,开启线程并调用Runnable接口子类的run()方法



实现方式和继承方式有什么不同呢?

实现方式好处:避免了单继承的局限性

在定义线程时,建议使用实现方式

存放线程代码位置不同:

继承Thread:线程代码存放在Thread子类的run()方法中

实现Runnable,线程代码存放在接口的子类run()方法中

注意:

Thread类本身也实现Runnable接口,Runnable的定义其实就是在确线程运行代码所存放的位置

示例代码2:

package com.itheima.day11;

class
Ticket1 implements Runnable{

private int
tick = 100;

public void run(){

while(true){

if(tick>0){

System.out.println(Thread.currentThread().getName()+" sale:"+tick--);

}

}

}

}

public class ThreadRunnableDemo {

public static void main(String[] args) {

Ticket1 t = new Ticket1();

//创建了一个线程

Thread t1 =
new Thread(t);

Thread t2 =newThread(t);

Thread t3 = new Thread(t);

Thread t4 = new Thread(t);

/**

* 分析:

*作用是开启线程,调用的是Thread类中的run()方法,但是此时的Ticket3实现的是

*Runnable接口,其中也有run方法,此时Thread中的run()中没有卖票的代码

*/

t1.start();

t2.start();

t3.start();

t4.start();

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: