Java多线程

1.1进程与线程

1.2Java的多线程实现

  在java中要想实现多线程可以用以下两种方式

    继承Thread类

    实现Runnable接口

1.2.1Thread类

  java.lang包会在程序运行时自动导入,所以不用手动编写import语句。

  一个类继承了Thread类之后,那么此类就具有了多线程的操作功能。

class MyThread implements Runnable{    // 实现Runnable接口,作为线程的实现类
    private String name ;        // 表示线程的名称
    public MyThread(String name){
        this.name = name ;        // 通过构造方法配置name属性
    }
    public void run(){    // 覆写run()方法,作为线程 的操作主体
        for(int i=0;i<10;i++){
            System.out.println(name + "运行,i = " + i) ;
        }
    }
};
View Code

  以上已经完成了一个线程的操作类,直接使用此类就可以完成功能。

  以上的程序是先执行完A之后再执行B线程,并没有达到所谓的并发执行的效果。

  因为以上的程序实际上还是按古老的形式,通过对象方法去调用,但是如果想要启动一个线程必须使用Thread类中定义的start()方法。

  一旦调用start()方法,实际上最终调用的就是run()方法。

class MyThread extends Thread{    // 继承Thread类,作为线程的实现类
    private String name ;        // 表示线程的名称
    public MyThread(String name){
        this.name = name ;        // 通过构造方法配置name属性
    }
    public void run(){    // 覆写run()方法,作为线程 的操作主体
        for(int i=0;i<10;i++){
            System.out.println(name + "运行,i = " + i) ;
        }
    }
};
public class ThreadDemo02{
    public static void main(String args[]){
        MyThread mt1 = new MyThread("线程A ") ;     // 实例化对象
        MyThread mt2 = new MyThread("线程B ") ;     // 实例化对象
        mt1.start() ;    // 调用线程主体
        mt2.start() ;    // 调用线程主体
    }
};
View Code

   从此处的效果来看,确实是并发执行的,那个线程先抢到了CPU资源,那个线程就执行。

问题:

  为什么不直接调用run()方法,而是通过strat()调用呢?

  如果要解决这样的难题,则要打开Thread类的定义,在JDK的src.zip中全部都是JAVA的原程序代码,直接找到java.lang.Thread类,就可以打开Thread类的定义。

class MyThread extends Thread{    // 继承Thread类,作为线程的实现类
    private String name ;        // 表示线程的名称
    public MyThread(String name){
        this.name = name ;        // 通过构造方法配置name属性
    }
    public void run(){    // 覆写run()方法,作为线程 的操作主体
        for(int i=0;i<10;i++){
            System.out.println(name + "运行,i = " + i) ;
        }
    }
};
public class ThreadDemo03{
    public static void main(String args[]){
        MyThread mt1 = new MyThread("线程A ") ;     // 实例化对象
        mt1.start() ;    // 调用线程主体
        mt1.start() ;    // 错误
    }
};
View Code

1.2.2Runnable接口

class MyThread implements Runnable{      // 实现Runnable接口,作为线程的实现类
  private String name ;                            // 表示线程的名称
  public MyThread(String name){
    this.name = name ;                       // 通过构造方法配置name属性
  }
  public void run(){ // 覆写run()方法,作为线程 的操作主体
    for(int i=0;i<10;i++){
      System.out.println(name + "运行,i = " + i) ;
    }
  }
};

  如果要想启动线程则肯定依靠Thread类,但是之前如果直接继承了Thread类,则可以将start()方法直接继承下来并使用,但是Runnable接口中并没有此方法。

Thread类的构造:

public Thread(Runnable target)

  就利用以上的构造方法,启动多线程。

class MyThread implements Runnable{    // 实现Runnable接口,作为线程的实现类
    private String name ;        // 表示线程的名称
    public MyThread(String name){
        this.name = name ;        // 通过构造方法配置name属性
    }
    public void run(){    // 覆写run()方法,作为线程 的操作主体
        for(int i=0;i<10;i++){
            System.out.println(name + "运行,i = " + i) ;
        }
    }
};
public class RunnableDemo01{
    public static void main(String args[]){
        MyThread mt1 = new MyThread("线程A ") ;     // 实例化对象
        MyThread mt2 = new MyThread("线程B ") ;     // 实例化对象
        Thread t1 = new Thread(mt1);
        Thread t2 = new Thread(mt2);             // 实例化Thread类对象
        t1.start();
        t2.start();
    }
};
View Code

  从运行效果可以发现,已经完成了多线程的功能。

1.3Thread类与Runnable接口

1.3.1Thread类与Runnable接口的联系

Thread定义:

public class Thread

extends Object

implements Runnable

  从定义格式上可以发现,Thread类也是Runnable接口的子类。

  从类的关系上来看,之前的做法非常类似于代理设计模式,Thread类完成比线程主体更多的操作。例如:分配CPU资源,判断是否已经启动等。

1.3.2Thread类与Runnable接口的区别

  使用Thread类在操作多线程的时候无法达到资源共享的目的,而使用Runnable接口实现的多线程操作可以实现资源共享。

class MyThread extends Thread{    // 继承Thread类,作为线程的实现类
    private int ticket = 5 ;        // 表示一共有5张票
    public void run(){    // 覆写run()方法,作为线程 的操作主体
        for(int i=0;i<100;i++){
            if(this.ticket>0){
                System.out.println("卖票:ticket = " + ticket--) ;
            }
        }
    }
};
public class ThreadDemo04{
    public static void main(String args[]){
        MyThread mt1 = new MyThread() ;     // 实例化对象
        MyThread mt2 = new MyThread() ;     // 实例化对象
        MyThread mt3 = new MyThread() ;     // 实例化对象
        mt1.run() ;    // 调用线程主体
        mt2.run() ;    // 调用线程主体
        mt3.run() ;    // 调用线程主体
    }
};
View Code

    发现一共卖了15张票,证明了三个线程各自卖各自的5张票,也就是说现在并没有达到资源共享的目的。

  因为在每一个MyThread对象中都包含各自的ticket属性。

  如果现在使用Runnable接口呢?同样启动多个线程,那么所有的线程将卖出共同的5张票。

class MyThread implements Runnable{    // 继承Thread类,作为线程的实现类
    private int ticket = 5 ;        // 表示一共有5张票
    public void run(){    // 覆写run()方法,作为线程 的操作主体
        for(int i=0;i<100;i++){
            if(this.ticket>0){
                System.out.println("卖票:ticket = " + ticket--) ;
            }
        }
    }
};
public class RunnableDemo02{
    public static void main(String args[]){
        MyThread mt = new MyThread() ;     // 实例化对象
        new Thread(mt).run() ;    // 调用线程主体
        new Thread(mt).run() ;    // 调用线程主体
        new Thread(mt).run() ;    // 调用线程主体
    }
};
View Code

  从运行效果来看,现在启动了三个线程,但三个线程一共才卖了5张票。所以达到了资源共享的目的。

1.3.3Thread类与Runnable接口的使用结论

1.4线程的状态

 

  实际上,线程调用start()方法的时候不是立刻启动的,而是要等待CPU进行调度。

2、总结

原文地址:https://www.cnblogs.com/jerry201907/p/11239893.html