1. 认识多线程
进程和线程
- 线程是在进程的基础上进行划分。进程是程序的一次动态执行过程,他经历了从代码加载、执行到执行完成的完整过程,这个过程也是进程本身从产生,发展到最终消亡的过程。
- 多线程是实现并发机制的一种有效手段。进程和线程一样,都是实现并发的一个基本单位。
Java的多线程实现
- 继承Thread类
- 实现Runnable接口
- Thread类
Thread类是在java.lang包中定义的,一个类只要继承了Thread类,此类就称为多线程操作类。在Threa子类之中,必须明确的覆写Thread类中的Run()方法,此方法为线程的主体。
多线程的定义语法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SNguYkBc-1610103102719)(https://uploader.shimo.im/f/xBNe7j0JnuGueHI5.png!thumbnail?fileGuid=VT8YkHRTjJdQt9dG)]
案例:
class XC extends Thread{
private String name;
public XC(String name){
this.name=name;
}
public void run(){
for(int i=0;i<10;i++){
System.out.println(name+"运行"+(++i));}}}
我们来测试一下线程
public static void main(String[] args) {
XC xc1=new XC("线程A");
XC xc2=new XC("线程B");
xc1.run();
xc2.run();}
运行结果:
运行结果是按顺序执行,并没有进行交替执行,只是因为上面的程序还是按照普通的方法调用,通过调用对象的方法,但是如果要想启动一个线程必须使用Thread类中的Start方法来启动多线程。
使用start方法后的运行结果
public static void main(String[] args) {
XC xc1=new XC("线程A");
XC xc2=new XC("线程B");
xc1.start();
xc2.start();}
可以看到现在两个线程进行并发执行,那个线程先抢到cpu时间片则那个线程先执行,这里我们看一下start的实现。
这里Start方法是调用run()方法,为什么我们直接调用run()方法却不能实现呢?
public synchronized void start() {
if (threadStatus != 0)
throw new IllegalThreadStateException();
group.add(this);
start0();
if (stopBeforeStart) {
stop0(throwableFromStop);}}
private native void start();
start()方法可能会抛出异常。
stopBeforeStart是一个boolean型变量。
native关键字表示的是一个由Java调用本机操作系统函数的一个关键字,在Java中运行Java程序调用本机的操作系统的函数以完成特定的功能。
如果需要实现多线程的话,则肯定需要操作系统的支持,因为多线操作中牵扯到一个抢占CPU的情况,要等待CPU进行调度,那么这一点肯定需要操作系统的底层支持,所以需要使用native调用本机的系统函数。
- 实现Runnable接口
在java中也可以通过实现Runnable接口的方式实现多线程,Runable接口中只定义了一个抽象的方法。
通过Runable接口实现多线程
实例:
class RunDemo implements Runnable{
private String name;
public RunDemo(String name){
this.name=name;
}
public void run(){
for(int i=0;i<3;i++){
System.out.println(name+"运行"+i);}}}
实现类:
public static void main(String[] args) {
RunDemo xc2=new RunDemo("线程A");
RunDemo xc3=new RunDemo("线程B");
Thread t1=new Thread(xc2);
Thread t2=new Thread(xc3);
t1.start();
t2.start();}
运行结果:
从运行效果可以发现,已经完成了多线程的功能。
Thread与Runnable接口
两者之间的联系
public class Thread
extends Object
implements Runnable
可以看出thread实现了Runnable接口,则可知道Thread是Runable的子类。
两者之间的区别
使用Thread类在操作多线程的时候无法达到资源共享的目的,而实现Runnable接口是可以实现资源共享的。
这里我们以三个窗口卖5张票为例来进行比较。
- 继承Thread类来进行实现
class T extends Thread{
private int ticketN=3;
private String name;
public T(String name){
this.name=name;
}
public void run(){
for(int i=0;i<10;i++) {
if (this.ticketN > 0) {
System.out.println(name + "卖票:ticket=" + ticketN--); }}}}
public class Ticket {
public static void main(String[] args) {
T t1=new T("窗口A");
T t2=new T("窗口B");
T t3=new T("窗口C");
t1.run();
t2.run();
t3.run();
}
}
运行结果:
这里可以发现每个线程都拥有独立的资源,每个线程都有3张票卖,说明资源不共享。
- 实现Runnable的方式
class R implements Runnable{
private int ticketN=3;
public void run(){
for(int i=0;i<10;i++) {
if (this.ticketN > 0) {
System.out.println( "卖票:ticket=" + ticketN--); }}}}
运行类:
public static void main(String[] args) {
R r1 = new R();
Thread t1=new Thread(r1);
Thread t2=new Thread(r1);
Thread t3=new Thread(r1);
t1.run();
t2.run();
t3.run();}
运行结果:
可以发现虽然创建了三个线程,但是三个线程一共卖出了5张票。
Thread和Runnable接口的使用结论
Runnable优点
- 适合多个相同程序代码的下次你去处理同一个资源。
- 可以避免由于单继承局限所带来的影响。
- 增强了程序的健壮性,代码能够被多个线程共享,代码与数据是独立的
综合runnable接口更好。
线程的状态
- 创建状态,准备还一个多线程的实例,Thread t=newThread();
- 就绪状态,调用start方法
- 运行状态:调用run()方法
- 阻塞状态,暂时停止执行,可能将资源交给其他线程使用。