实现多线程的几种方法-Java

实现 Runnable接口方式实现多线程

自定义类实现Runnable接口,将自定义类的对象传入Thread构造函数的参数。

Thread构造函数
Thread(Runnable target, String name)
分配一个新的 Thread对象

好处是不影响自定义类的继承,自定义类可以作为同一个资源供多个线程使用。

public class Mythread implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i <50; i++) {
            System.out.println(i);
        }
    }
}
public class MytheadDemo {
    public static void main(String[] args) {
        Mythread mythread1=new Mythread();
        Thread thread1=new Thread(mythread1,"线程1");
        thread1.run();

    }
}

实现Runnable接口底层是重写了Runnable的run方法,当new Thread会判断Runnable方法的run方法是否为空不为空则调用Runnable的run方法,当为空则调用自己的run方法。但是当如果我们自己写了Thread的run方法,那就是重写了Thread的run方法,那么就不会执行下面这个判断Runnable是否为空了!具体例子下面匿名类写法中有详细写。
在这里插入图片描述
在这里插入图片描述

继承Thead方法实现多线程

public class Thread
extends Object
implements Runnable

  • 线程是程序中执行的线程。 Java虚拟机允许应用程序同时执行多个执行线程。

创建一个新的执行线程有两种方法:

  • 一:是将一个类声明为Thread的子类。 这个子类应该重写Thread类的方法run。 然后可以分配并启动子类的实例。
    1:创建Mythead继承Thread类
    2:重写方法run
    3:创建Mythread对象
    4:启动线程

  • 需要用到的两个Teread类的方法
    1:public void run() 用来封装被线程重写的方法。 Thread的Thread应该覆盖此方法。
    2:public void start()导致此线程开始执行; Java虚拟机调用此线程的run方法。结果是两个线程同时运行:当前线程(从调用返回到start方法)和另一个线程(执行其run方法)。 不止一次启动线程是不合法的。 特别地,一旦线程完成执行就可能不会重新启动。
    异常 :IllegalThreadStateException - 如果线程已经启动。

public class Mythread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i <50; i++) {
            System.out.println(i);
        }
    }
}
public class MytheadDemo {
    public static void main(String[] args) {
        Mythread thread1=new Mythread();
        Mythread thread2=new Mythread();
        thread1.start();
        thread2.start();
    }
}

匿名内部类


/**
 *匿名内部类的方式启动线程
 */
public class T2 {
    public static void main(String[] args) {
 
        new Thread(){
            public void run(){
                System.out.println("thread1 start ... ");
            }
        }.start();
 
 
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("thread2 start .... ");
            }
        }).start();
 
    }
}

第1段相当于继承Thread的方式;第二段相当于实现Runnable的方式。

  • 用lambda写法,下面两段代码相同效果,第二种更简洁。注意:用lambda方法进行简化,类或者接口只能有一个方法(Runnable只有一个方法)一个方法的接口用@FunctionalInterface修饰。
  • 在这里插入图片描述
public static void main(String[] args) {
        Runnable runnable=new Runnable() {
            @Override
            public void run() {
                System.out.println("匿名内部类写法");
            }
        };
        Thread thread=new Thread(runnable);
        thread.start();
    }
public static void main(String[] args) {
        Runnable runnable= () -> { System.out.println("匿名内部类写法,用lambda写法");};
        Thread thread=new Thread(runnable);
        thread.start();
    }
public static void main(String[] args) {
        Thread thread=new Thread(() -> { System.out.println("匿名内部类写法");});
        thread.start();
    }
  • 第二种
    public Thread(Runnable target)分配一个新的Thread对象。 该构造函数具有与Thread (null, target, gname)相同的效果,其中gname是新生成的名称。 自动生成的名称格式为"Thread-"+ n ,其中n为整数。
    参数
    target - 启动此线程时调用其run方法的对象。 如果null ,这个类run方法什么都不做。

  • 将上述两个方法合并:

package com.yy.concurrent.base1;
 
/**
 *匿名内部类的方式启动线程
 */
public class T2 {
    public static void main(String[] args) {
 
 
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("runnable");
            }
        }){
            public void run(){
                System.out.println("sub");
            }
        }.start();
 
    }
}

最终输出结果是是:sub。为什么会这样呢?这就是重写导致的。
在这里插入图片描述
此时target不为空,应该是执行target.run(),即输出结果是Runnable,但是注意注意!!!!我们我看我们的代码,我们再T1类里面重写了run方法,所以执行的是重写的方法!
在这里插入图片描述
将上面的用普通方法写结果一样,Thread如果不重写run方法那么就运行的是Runnable的,如果重写那么运行的是Thread的run方法。

public static void main(String[] args) {
        Runnable runnable =new Runnable() {
            @Override
            public void run() {
                System.out.println("runnable的run");
            }
        };
        Thread thread=new Thread(runnable){
            @Override
            public void run() {
                System.out.println("thread的run方法");
            }
        };
        thread.start();
    }

在这里插入图片描述

通过Callable和FutureTask创建线程

a:创建Callable接口的实现类 ,并实现Call方法
b:创建Callable实现类的实现,使用FutureTask类包装Callable对象,该FutureTask对象封装了Callable对象的Call方法的返回值
c:使用FutureTask对象作为Thread对象的target创建并启动线程
d:调用FutureTask对象的get()来获取子线程执行结束的返回值

public class ThreadDemo03 {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub

        Callable<Object> oneCallable = new Tickets<Object>();
        FutureTask<Object> oneTask = new FutureTask<Object>(oneCallable);

        Thread t = new Thread(oneTask);

        System.out.println(Thread.currentThread().getName());

        t.start();

    }

}

class Tickets<Object> implements Callable<Object>{

    //重写call方法
    @Override
    public Object call() throws Exception {
        // TODO Auto-generated method stub
        System.out.println(Thread.currentThread().getName()+"-->我是通过实现Callable接口通过FutureTask包装器来实现的线程");
        return null;
    }   
}

Interface Callable
这是一个功能界面,因此可以用作lambda表达式或方法引用的赋值对象。
Callable接口类似于Runnable ,因为它们都是为其实例可能由另一个线程执行的类设计的。 然而,A Runnable不返回结果,也不能抛出被检查的异常。
该Executors类包含的实用方法,从其他普通形式转换为Callable类。

通过线程池创建线程

public class ThreadDemo05{

    private static int POOL_NUM = 10;     //线程池数量

    /**
     * @param args
     * @throws InterruptedException 
     */
    public static void main(String[] args) throws InterruptedException {
        // TODO Auto-generated method stub
        ExecutorService executorService = Executors.newFixedThreadPool(5);  
        for(int i = 0; i<POOL_NUM; i++)  
        {  
            RunnableThread thread = new RunnableThread();

            //Thread.sleep(1000);
            executorService.execute(thread);  
        }
        //关闭线程池
        executorService.shutdown(); 
    }   

}

class RunnableThread implements Runnable  
{     
    @Override
    public void run()  
    {  
        System.out.println("通过线程池方式创建的线程:" + Thread.currentThread().getName() + " ");  

    }  
}  
发布了43 篇原创文章 · 获赞 12 · 访问量 1400

猜你喜欢

转载自blog.csdn.net/qq_42411214/article/details/104645678