Java多线程学习与实现

一,什么是多线程

1.首先要明白:进程与线程的关系,很形象的例子,进程是线程的爹
1.单进程单线程:一个人在搬一堆砖
2.单进程多线程:多个人在搬一堆砖
3.多进程单线程:多个人每个人在自己的一堆砖**
2.使用多线程的优点(相对使用多进程来说):

1.进程之间不能共享内存,但线程之间共享内存非常容易。
2.系统创建线程所分配的资源相对创建进程而言,代价非常小

二、Java中实现多线程的3种方法介绍和比较

1.继承Thread类

继承Thread类,需要覆盖方法 run()方法,
在创建Thread类的子类时需要重写 run(),加入线程所要执行的代即可。

public class MyThread extends Thread {
    
      
  public void run() {
    
      
   System.out.println("This is extends Thread");  
  }  
}  
MyThread myThread1 = new MyThread();  
MyThread myThread2 = new MyThread();  
myThread1.start();  
myThread2.start();
2.实现Runnable接口

如果要实现多继承就得要用implements,Java 提供了接java.lang.Runnable 来解决上边的问题。

Runnable是可以共享数据的,多个Thread可以同时加载一个Runnable, 当各自Thread获得CPU时间片的时候开始运行Runnable,Runnable里面的资源是被共享的,所以使用Runnable更加的灵活。
PS:需要解决共享之后产生的资源竞争问题。

public class ThreadDemo1{
    
    
    public static void main(String[] args) {
    
    
        //为了启动MyThread,需要首先实例化一个Thread,并传入自己的MyThread实例:
        MyThread myThread=new MyThread();
        Thread thread=new Thread(myThread);
        thread.start();//开启线程
    }
}
class MyThread implements Runnable{
    
    

    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see Thread#run()
     */
    @Override
    public void run() {
    
    
        System.out.println("This is implements Runnable");
    }
}

3.实现Callable接口

Runnable是执行工作的独立任务,但是它不返回任何值。如果你希望任务在完成的能返回一个值,那么可以实现Callable接口而不是Runnable接口。在Java SE5中引入的Callable是一种具有类型参数的泛型,它的参数类型表示的是从方法call()(不是run())中返回的值。

package cn.huangt.java_learn_notes.multithread;

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

/**
 * Callable接口实现多线程
 */
public class CallableImpl implements Callable<String> {
    
    
    
    private String acceptStr;
    
    public CallableImpl(String acceptStr) {
    
    
        this.acceptStr = acceptStr;
    }

    public String call() throws Exception {
    
    
        // 任务阻塞1秒,并且增加一些信息返回
        Thread.sleep(1000);
        return this.acceptStr + " 增加一些字符并返回";
    }
    
    public static void main(String[] args) throws Exception {
    
    
        Callable<String> callable = new CallableImpl("Callable测试");
        FutureTask<String> task = new FutureTask<String>(callable);
        // 创建线程
        new Thread(task).start();
        long beginTime = System.currentTimeMillis();
        // 调用get()阻塞主线程,反之,线程不会阻塞
        String result = task.get();
        long endTime = System.currentTimeMillis();
        System.out.println("hello : " + result);
        
        // endTime 和 beginTime是不一样的,因为阻塞了主线程
        System.out.println("cast : " + (endTime - beginTime) / 1000 + " second!");
    }
}

/*
输出内容===
hello : Callable测试 增加一些字符并返回
cast : 1 second!
*/

三 Runnable、Thread、Callable总结

3.1实现Runnable接口相比继承Thread类有如下优势

1)可以避免由于Java的单继承特性而带来的局限
2)增强程序的健壮性,代码能够被多个线程共享,代码与数据是独立的
3)适合多个相同程序代码的线程去处理同一资源的情况
4)线程池只能放入实现Runable或Callable类线程,不能直接放入继承Thread的类

3.2实现Runnable接口和实现Callable接口的区别

1)Runnable是自从java1.1就有了,而Callable是1.5之后才加上去的
2)实现Callable接口的任务线程能返回执行结果,而实现Runnable接口的任务线程不能返回结果
3)Callable接口的call()方法允许抛出异常,而Runnable接口的run()方法的异常只能在内部消化,不能继续上抛
4)加入线程池运行,Runnable使用ExecutorService的execute方法,Callable使用submit方法

注:Callable接口支持返回执行结果,此时需要调用FutureTask.get()方法实现,此方法会阻塞主线程直到获取返回结果,当不调用此方法时,主线程不会阻塞
参考文章: https://www.jianshu.com/p/9e489390fc46

猜你喜欢

转载自blog.csdn.net/qq_44758515/article/details/108691574