一、进程与线程
1、进程
针对系统而言,是操作系统中的一个执行单元。
对于Windows系统来说就是一个.exe程序。
2、多进程
系统同时执行多个应用程序。
DOS单进程操作系统只能执行一个进程,一个进程执行完才能执行另一个进程。
单核CPU:每次只能执行一个程序,执行多个程序其实是在程序中不停地切换,只不过切换的速度超过了人的感知,让人觉得可以同时执行多个程序。在系统中执行的程序越多执行的速度就越慢,因为要在多个程序中不停地切换。
3、线程
线程是一个程序内部的顺序控制流,线程是针对程序(进程:一个程序代表一个进程),表示程序中一个线索。
4、多线程
程序中多个执行线索。
例如:暴风播放器可以一边下载一边看。
5、为什么有使用多线程?
使用多线程能提高程序的执行效率,提高用户的体验效果。
6、进程与线程的区别和联系
(1)每个进程都有独立的代码和数据空间,进程的切换的开销很大。
(2)同一类线程共享代码和数据空间,每个线程有独立运行的栈和程序计数器,程序切换的开销小。
二、Java中多线程实现
(一)Java中多线程实现思路
1、创建线程类
继承Thread类
或
实现Runnable接口
2、通过Thread类构造器来创建线程对象
Thread()
Thread(Runnable target)
3、通过start()方法激活线程对象
4、线程运行
(二)多线程实现的两种方式
1、创建线程的两种方式–线程类
(1)继承Thread类–java.lang.Thread
(2)实现Runnable接口–java.lang.Runnable
2、run()方法–线程运行体
要将一段代码(线程体)在一个新的线程上运行,该代码应该在一个线程类的run()函数中。
(1)写一个类继承Thread类,且必须重写Thread类中的run()方法。
(2)写一个类实现Runnable接口,且必须覆盖Runnable接口中的run()方法。
3、方法一:继承Thread类实现多线程
/*
* 继承Thread类实现多线程
* 1、定义一个类去继承Thread类并重写run()方法
* 2、创建线程对象
* 3、调用start()方法激活线程
*/
public class TestTread {
public static void main(String[] args) {
//创建线程对象mythread1
MyThread mythread1=new MyThread();
//通过mythread1线程对象调用线程方法Set()为线程mythread1设置名称
mythread1.setName("线程1");
//创建线程对象mythread2
MyThread mythread2=new MyThread();
//通过mythread2线程对象调用线程方法Set()为线程mythread2设置名称
mythread2.setName("线程2");
//调用start()方法,激活进程
mythread1.start();
mythread2.start();
System.out.println(Thread.currentThread().getName()+" is over...");
}
}
//定义一个类去继承Thread类
class MyThread extends Thread{
//定义常量count
int count=100;
//重写run()方法,run方法包含的是线程的运行代码
public void run()
{
//利用for()循环进行打印
for(int i=0;i<5;i++)
{
//Thread.currentThread().getName()获取当前线程的名字
System.out.println(Thread.currentThread().getName()+"\t"+count--);
}
}
}
4、方法二:实现Runnable接口实现多线程
/*
* 实现Runnable接口实现多线程
* 1、定义一个类去实现Runnable接口并重写run()方法
* 2、创建实现类对象
* 3、创建线程对象
* 4、调用start()方法激活线程
*/
public class TestRunnable {
public static void main(String[] args) {
//创建实现类对象
MyRunnable runn=new MyRunnable();
//创建线程对象,线程类Thread必须调用业务类MyRunnable--runn才能实现去干活
Thread th1=new Thread(runn);
//通过线程对象调用线程方法Set()为线程设置名称
th1.setName("线程1");
//创建线程对象,线程类Thread必须调用业务类MyRunnable--runn才能实现去干活
Thread th2=new Thread(runn);
//通过线程对象调用线程方法Set()为线程设置名称
th2.setName("线程2");
//通过线程对象调用线程方法start()为激活线程
th1.start();
th2.start();
//Thread.currentThread().getName():获取当前线程的名字
System.out.println(Thread.currentThread().getName()+" is over...");
}
}
//、定义一个类去实现Runnable接口
class MyRunnable implements Runnable{
//定义count常量
int count=100;
//重写run()方法
public void run() {
//利用for()循环进行打印
for(int i=0;i<5;i++)
{
//Thread.currentThread().getName():获取当前线程的名字
System.out.println(Thread.currentThread().getName()+":\t"+count--);
}
}
}
(三)多线程访问同一数据的问题
1、在继承Thread类实现多线程中,创建了两个对象,所以mythread1和mythread2不是公用一个数据空间的,每new一个就新建一个数据空间,一共新建了两个数据空间。count成员变量都是每个对象独有的。如果想要实现共用一个数据空间的话可以把count定义为static int count=100;但是是伪方法,在实际的开发中一般不会用。
//创建线程对象mythread1
MyThread mythread1=new MyThread();
//创建线程对象mythread2
MyThread mythread2=new MyThread();
2、在实现Runnable接口实现多线程中,创建了一个实现类对象runn,而创建的两个线程对象th1、th2都是在实现类对象runn基础上创建的,所以他们共用一个数据空间,两个线程的操作都是在同一count上,与他们执行的先后无关。
//创建实现类对象
MyRunnable runn=new MyRunnable();
//创建线程对象,线程类Thread必须调用业务类MyRunnable--runn才能实现去干活
Thread th1=new Thread(runn);
//创建线程对象,线程类Thread必须调用业务类MyRunnable--runn才能实现去干活
Thread th2=new Thread(runn);
三、比较两种实现线程方法的优劣
1、通过继承Thread实现线程,更容易理解与实现,不方便实现多进程共享同一数据空间。
2、通过实现Runnable接口创建线程,理解不易实现困难,容易实现多线程共享同一数据空间。因为它是实现接口的,所以还可以继承其他的类进行拓展。
四、线程的生命周期
1、创建
MyThread mythread1=new MyThread();
2、就绪
mythread1.start();
3、执行
run()方法
4、阻塞
sleep()、yield()
5、终止
(1)run()方法执行完毕(正常结束)
(2)Interrupt()结束中断进程(非正常结束)