多线程:
进程:正在进行中的程序(直译);
对应的是一个程序在内存中开辟的空间。
线程:就是进程中的一个负责程序执行的控制单元,(执行路径)
一个进程中可以有多条执行路径,称之为多线程。
一个进程当中,至少要有一个线程。线程的出现,负责程序的执行。
多线程的目的:开启多个线程是为了同时运行多部分代码
多线程的任务:
每一个线程都有自己运行的内容。这个内容可以称为线程要执行的任务。
我们都要知道,控制程序运行的控制器为cpu ,所以在某一个时刻,只有一个程序来执行。只不过控制路径切换的频率很快,在表面上看好像是同时进行的。其实只是CPU切换的速率特别快。而当开启的程序过多时,处理器处理每一个程序的频率降低,从而导致效率降低。
多线程的优缺点:
好处:解决了多个程序同时运行的问题。
弊端:线程太多会导致效率的降低。
在Java中,对线程的认识:
vm启动时就启动了多个线程,至少有两个线程可以分析的出来。
1.执行main函数的线程
该线程的任务代码都定义在main函数中
2.负责垃圾回收的线程。
创建线程的方法:
第一种:继承Thread类。
java.lang.Thread 类: 线程,Java虚拟机允许应用程序并发的运行多个执行线程。
将类声明为Thread的子类,该子类应该重写Thread类的run方法。
步骤:
1、定义一个类继承Thread类。
2、覆盖Thread类中的run方法。
3、创建线程对象(直接创建Thread类的子类对象);
4、调用start方法,开启线程,并调用线程的任务:run方法。
可以通过Thread类的getName()方法获取线程的名称名称形式为:Thread——数字;
currentThread()方法:返回当前执行线程的对象;
主线程的名字就是:main;
package ThreadDemo;
public class ThreadDemo1 {
/**
* @param args
*/
public static void main(String[] args) {
/*
* 为什么要继承Thread并复写run方法的原因:
创建线程的目的是为了开启一条执行路径,去运行指定的代码和其他代码实现同时运行。
而运行的指定代码就是这个执行路径的任务。
JVM创建的主线程的任务都定义在了主函数中。
而自定义的线程它的任务在哪里?
Thread类用于描述线程,线程是需要任务的。所以Thread类也对任务进行描述。
这个任务就通过Thread类中的run方法来体系那。也就是说,run方法就是封装自定义线程运行任务的函数。
run方法中定义就是线程要运行的任务代码。
开启线程是为了运行指定代码。所以只有继承Thread类,并复写run方法。
将运行的代码定义在run方法中即可。
*/
Demo1 d1 = new Demo1("wangci");
Demo1 d2 = new Demo1("xiaoqiang");
//d1.run();//调用run方法。就会是一个标准的顺序执行方式;应该使用start方法来启动线程。
//d2.run();
d1.start();//开启线程,调用run方法;
d2.start();
System.out.println("main...."+Thread.currentThread().getName());
}
}
class Demo1 extends Thread{
private String name;
Demo1(String name){
this.name = name;
//super(name);
}
public void run(){
show();
}
public void show(){
for(int x=0;x<20;x++){
System.out.println(name+"......"+getName());
}
}
}
创建线程的第二种方式:
第一种方式中的弊端:
当一个类有父类的时候,就不能再继承Thread类,从而不能实现线程。这时,可以实现Runable接口的方式来实现多线程。
引出第二种实现多线程的方法:实现Runnable接口实现多线程。
步骤:
1、定义类实现Runnable接口。
2、覆盖接口中的run方法,将线程的任务代码封装到run方法中。
3、通过Thread类创建线程对象,并将Runnable接口的子类对象作为Thread类的构造函数的参数进行传递。
原因:因为线程的任务都封装在Runnable接口子类对象的run方法中。所以要在线程对象创建时就必须明确要运行的任务。
4、调用线程对象的start方法开启线程。
Runable接口应该由哪些打算通过某一线程执行其实例的类来实现,类必须定义一个 称为run的无参数方法。
package ThreadDemo;
public class ThreadRunnableDemo1 {
/**
* @param args
*/
public static void main(String[] args) {
Demo2 d1 = new Demo2();
Demo2 d2 = new Demo2();
Thread t1 = new Thread(d1);//使用Thread类的构造函数:Public Thread(Runnable target);引入线程执行对象。
Thread t2 = new Thread(d2);
t1.start();
t2.start();
}
}
class Demo2 implements Runnable// extends Fu//由于Java不支持多继承。这时使用继承Thread类的方法实现多线程,就不易实现。
//通过接口的形式扩展Demo类的功能,让其中的内容可以作为线程的任务运行。
{
public void run()
{
show();
}
public void show()
{
for(int x = 0;x<20;x++)
{
System.out.println(Thread.currentThread().getName()+"......"+x);
}
}
}
/*class Fu
{
}*/
第二种方法的好处:
1、如果继承了Thread类,就称为了Thread类对象中的一员,并拥有了Thread对象中的所有方法。而实现了Runnable接口,它仅仅是将线程的任 务进行了对象的封装。这是,仅仅是将要进行多线程的任务封装。实现多线程,只需要创建Thread类对象,并引入线程任务引入即可。
实现Runnable和继承Thread类的区别(实现Runnable接口的好处):
1、将线程的任务从线程的子类中分离出来,进行了单独的封装。
按照面向对象的思想将任务封装成了对象。
2、避免了Java单继承的局限性。
对比两种方式,我们可以得出 创建线程的第二种方式较为常用。