资讯详情

2022.0709学习Java笔记之多线程编程(一)

就操作系统而言,民用系统最早可用DOS,但是传统的DOS系统有一个特点:电脑病毒出现后,系统会死亡,因为传统DOS该系统采用单过程处理方法。windows在时代,采用多过程处理方法,多个程序将在同一时间段并发执行,轮流强占CPU资源。

然而,过程的启动和破坏仍然非常缓慢。因此,后来人们开始尝试进一步优化过程,从而产生了线程的概念,即线程是在过程的基础上扩展的。线程的启动和销毁将比过程更快。多个线程可以在一个过程中划分,如果过程消失,线程也会消失,Java支持多线程编程的少数语言之一

如果你想实现多线程的开发,你必须像主类一样需要一个线程的主类,但这个类不能单独定义,必须继承Thread类或实现Runnable接口(如果从实际开发来看,必须是Runnable接口)。 1. 继承Thread类 线程的主要类别只需要通过extends 关键字继承Thread类,然后这个类可以用于线程控制,当继承时Thread用户还需要重复Thread类之中的run()方法“public void run)”。 例子:定义线程的主题类别

class MyThread extends Thread{     private String name;    ////理解为对象的名称     public MyThread(String name){         this.name = name;     }     @Override      public void fun(){   ///主线程方法         for(int x = 0 ; x < 10 ; x   ){             System.out.println(this.name   ", x= "  x);         }     } }

此时每一个MyThread类的对象是一个线程,因此可以产生多个线程。

但是,当线程主体类定义完成后,必须通过对象访问,但调用的不是类中runO方法,而是Thread类的start()方法:public void start)。调用此方法相当于调用run()方法。 例子:启动多线程。

public class TextDemo {     public static void main(String[] args){         MyThread mtA = new MyThread("线程A");         MyThread mtB = new MyThread("线程B");         MyThread mtC = new MyThread("线程C");         mtA.start();         mtB.start();         mtC.start();     } } 

若使用runO事实上,该方法只是一种普通的调用方法,将按顺序执行,如果调用是start()方法意味着将启动多线程,多线程并发运行。 问题:通过简短的分析,我们应该已经知道多线程的基本运行过程,但为什么要通过呢?start()来调用run()呢? 为便于理解,打开关于Thread类中startO定义方法:

public synchronized void start(){         if(threadstatus != 0)             throw newIllegalThreadstateException();         group.add(this);         boolean started = false;         try {             start0();             started = true;.         }finally {             try {                 if (!started) {                     group.threadStartFailed(this);                 }             }catch (Throwable ignore){             }         }     }

本方法会抛出一个“IllegalThreadStateException异常,但如果是手工使用的话throw应使用抛出异常try..catch处理是对的。但此时没有强制性要求,因为通过观察IllegalThreadStateException继承结构:

java.lang.Object

java.lang.Throwable java.lang.Exception java.lang.RuntimeException java.lang.IllegalArgumentException java.lang.IllegalThreadStateExceptione

因为RuntimeException子类,通常当一个线程重复启动时就会抛出这种异常。因此,一个线程只能启动一次。

在调用中可以发现start()方法自动调用start()方法,而在start在方法的声明中发现了一个()native关键字,此时关键字表示代码将通过本地原始函数实现。 必须操作线程CPU每个操作系统的资源调度是不同的,所以这种方法实际上是由JVM实现时,只给出抽象方法的名称,具体实现将根据不同的操作系统重写,从而实现可移植性。

因此,当用户执行时,可以得出结论start方法意味着操作系统的资源部署将在部署后实施run()方法,即任何时候只要启动多线程,都必须使用Thread类之中的start()方法。

2.实现Runnable接口. 不建议使用类与类之间的继承,但类实现接口是推荐功能Java为了解决多线程单继承的局限性,还提供了一个Runnable接口,用户只需要让线程的主要类别实现Runnable接口即可。 范例:观察Runnable 界面定义结构.

public interface Runnable{         public void run(); }

范例:使用Runnable定义线程主体类

class MyThread implements Runnable{     private String name;        public MyThread(String name){         this.name = name;     }     public void run(){   ///主线程方法         for(int x = 0 ; x < 10 ; x   ){             System.out.println(this.name   ", x= "  x);         }     } }

通过之前的分析可以得出结论,只要线程的启动必须依赖于Thread类的start)如果说一个类现在直接继承了方法Thread类,然后就可以继承了start()方法,但此时实现了Runnable接口,那就没有了start可被继承。然后观察下面Thread类中结构方法的定义:public Thread(Runnable target)”。发现可以接收一个Runnable接口子类对象

例子:启动多线程

public class TextDemo {     public static void main(String[] args){         MyThread mtA = new MyThread("线程A");         MyThread mtB = new MyThread("线程B");         MyThread mtC = new MyThread("线程C");         new Thread(mtA).start();         new Thread(mtB).start();         new Thread(mtC).start();     } }

此时两者的功能完全是同的,但是很明显,使用Runnable要比使用Thread更加合理。

两种方式实现的区别

  通过一系列的分析之后已经清楚了多线程的两种实现方式,但是这两种方式从结构上讲一定使用的是Runnable,是除了这一点之外,还有其它的区别吗?   那么首先来观察一下Thread类的定义:

public class Thread extends Object implements Runnable

发现原来Thread类也实现了Runnable接口,于是一件很有意思的事情发生了。

  从结构上讲Thread是一个代理类的结构设计,但是又不那么完整。如果是一个纯粹的代理设计模式,那么用户应该调用的是Thread类的run()方法,但是现在调用的却是start()方法(并不是Runnable接口提供的方法)所以在整个操作之中虽然形式是代理结构,但是最终还是有差异的,而这个差异也是由于历史原因造成的。   除了这个基本的联系之外,还有一点不算区别的小区别:使用Runnable接口实现的多线程多线程要比使用Thread类实现的多线程更容易表示出数据共享的概念。 范例:编写一个简单的卖票程序,利用Thread类实现(产生三个线程对象一起卖票) 

package cn.mldn.demo;

class MyThread extends Thread{
    private int ticket = 5;
    public void run(){   //线程的主方法
        for(int x = 0 ; x < 20 ; x++ ){
            if(this.ticket > 0){
                System.out.println("卖票:ticked = " + this.ticket--);
            }
        }
    }
}
public class TextDemo {
    public static void main(String[] args){
        new MyThread().start() ;    //一个线程
        new MyThread().start() ;    //二个线程
        new MyThread().start() ;    //三个线程
    }
}

此时发现每个线程对象都有五张票,不符合要求

范例:利用Runnable接口实现

package cn.mldn.demo;

class MyThread implements Runnable{
    private int ticket = 5;
    public void run(){   //线程的主方法
        for(int x = 0 ; x < 20 ; x++ ){
            if(this.ticket > 0){
                System.out.println("卖票:ticked = " + this.ticket--);
            }
        }
    }
}
public class TextDemo {
    public static void main(String[] args){
        MyThread mt = new MyThread();
        new Thread(mt).start() ;    //一个线程
        new Thread(mt).start() ;    //二个线程
        new Thread(mt).start() ;    //三个线程
    }
}

请解释出多线程两种实现方式的区别?

  • 多线程的两种实现方式:继承Thread类、实现Runnable接口;
  • 如果继承了Thread类,那么会受到单继承局限,而且不方便表示出数据共享的概念,Thread类是Runnable接口的子类;
  • 如果实现了Runnable接口,那么将不受到单继承的影响,同时可以方便的表示出数据共享操作
  • 但是不管使用何种方式,最终一定要通过Thread类的 startO方法才可以启动多线程。

标签: mtc本安型磁致伸缩位移传感器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台