本帖最后由 黄玉昆 于 2013-2-16 14:38 编辑
一、概述: 1、线程是什么呢? 我们先来说一说比较熟悉的进程吧,之后就比较容易理解线程了。所谓进程,就是一个正在执行(进行)中的程序。每一个进程的执行都有一个执行顺序,或者说是一个控制单元。简单来说,就是你做一件事所要进行的一套流程。线程,就是进程中的一个独立的控制单元;也就是说,线程是爱控制着进程的执行。一个进程至少有一个线程,并且线程的出现使得程序要有效率。打个比方说,在仓库搬运货物,一个人搬运和五个人搬运效率是不一样的,搬运货物的整个程序,就是进程;每一个人搬运货物的过程,就是线程。 2、java中的线程: 在java中,JVM虚拟机启动时,会有一个进程为java.exe,该程序中至少有一个线程负责java程序的执行;而且该程序运行的代码存在于main方法中,该线程称之为主线程。其实,JVM启动时不止有一个线程(主线程),由于java是具有垃圾回收机制的,所以,在进程中,还有负责垃圾回收机制的线程。 3、多线程的意义: 透过上面的例子,可以看出,多线程有两方面的意义: 1)提高效率。 2)清除垃圾,解决内存不足的问题。 二、自定义线程: 线程有如此的好处,那要如何才能通过代码自定义一个线程呢?其实,线程是通过系统创建和分配的,java是不能独立创建线程的;但是,java是可以通过调用系统,来实现对进程的创建和分配的。java作为一种面向对象的编程语言,是可以将任何事物描述为对象,从而进行操作的,进程也不例外。我们通过查阅API文档,知道java提供了对线程这类事物的描述,即Thread类。创建新执行线程有两种方法: 一)创建线程方式一:继承Thread类。 1、步骤: 第一、定义类继承Thread。 第二、复写Thread类中的run方法。 第三、调用线程的start方法。分配并启动该子类的实例。 start方法的作用:启动线程,并调用run方法。 - <font face="Arial" size="1">class Demo extends Thread
- {
- public void run()
- {
- for (int i=0;i<60;i++)
- System.out.println(Thread.currentThread().getName() + "demo run---" + i);
- }
- }
- class Test2
- {
- public static void main(String[] args)
- {
- Demo d1 = new Demo();//创建一个对象就创建好了一个线程
- Demo d2 = new Demo();
- d1.start();//开启线程并执行run方法
- d2.start();
- for (int i=0;i<60;i++)
- System.out.println("Hello World!---" + i);
- }
- }</font>
复制代码2、运行特点: A.并发性:我们看到的程序(或线程)并发执行,其实是一种假象。有一点需要明确:;在某一时刻,只有一个程序在运行(多核除外),此时cpu是在进行快速的切换,以达到看上去是同时运行的效果。由于切换时间是非常短的,所以我们可以认为是在并发进行。 B.随机性:在运行时,每次的结果不同。由于多个线程都在获取cpu的执行权,cpu执行到哪个线程,哪个线程就会执行。可以将多线程运行的行为形象的称为互相抢夺cpu的执行权。这就是多线程的特点,随机性。执行到哪个程序并不确定。 3、覆盖run方法的原因: 1)Thread类用于描述线程。该类定义了一个功能:用于存储线程要运行的代码,该存储功能即为run方法。也就是说,Thread类中的run方法用于存储线程要运行的代码,就如同main方法存放的代码一样。 2)复写run的目的:将自定义代码存储在run方法中,让线程运行要执行的代码。直接调用run,就是对象在调用方法。调用start(),开启线程并执行该线程的run方法。如果直接调用run方法,只是将线程创建了,但未运行。 二)创建线程方式二:实现Runnable接口 1、步骤: 第一、定义类实现Runnable接口。 第二、覆盖Runnable接口中的run方法。 第三、通过Thread类建立线程对象。要运行几个线程,就创建几个对象。 第四、将Runnable接口的子类对象作为参数传递给Thread类的构造函数。 第五、调用Thread类的start方法开启线程,并调用Runnable接口子类的run方法。 - <font size="1" face="Arial">//多个窗口同时卖票
- class Ticket implements Runnable
- {
- private int tic = 20;
- public void run()
- {
- while(true)
- {
- if (tic > 0)
- System.out.println(Thread.currentThread().getName() + "sale:" + tic--);
- }
- }
- }
- class TicketDemo
- {
- public static void main(String[] args)
- {
- Ticket t = new Ticket();
- Thread t1 = new Thread(t);//创建一个线程
- Thread t2 = new Thread(t);//创建一个线程
- Thread t3 = new Thread(t);//创建一个线程
- Thread t4 = new Thread(t);//创建一个线程
- t1.start();
- t2.start();
- t3.start();
- t4.start();
- }
- }
- </font>
复制代码2、说明: A.步骤2覆盖run方法:将线程要运行的代码存放在该run方法中。 B.步骤4:为何将Runnable接口的子类对象传给Thread构造函数。因为自定义的run方法所属对象为Runnable接口的子类对象,所以让线程指定对象的run方法,就必须明确该run方法所属的对象。 三)实现方式与继承方式有何区别: 1、实现方式:避免了单继承的局限性。 在定义线程时,建议使用实现方式。 2区别: 继承Thread:线程代码存放在Thread子类的run方法中。 实现Runnable:线程代码存在接口的子类run方法中。 需要注意的是:局部变量在每一个线程中都独有一份。 四)Thread类中的一些方法简介: 1、获取线程名称:getName() 每个线程都有自己默认的名称,获取格式:对象.getName();打印后,显示为:Thread-编号(从0开始),也就是说,线程一为:Thread-0,线程二为:Thread-1。也可以获取当前线程对象的名称,通过currentThread().getName()。如上面方式二的结果为
file:///C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\msohtml1\01\clip_image002.jpg 2、设置线程名称:setName()或构造函数 可以通过setName()设置线程名称,或者通过含有参数的构造函数直接显式初始化线程的名称,如Test(Stringname)。
|