【Java多线程】(一)多线程实现

最近要忙着招工作了,发现现在招Java开发的公司特别喜欢问多线程的问题,因此就在这自己小总结一下啦~

一:进程线程的区别:

这个问题大家基本都会问。首先,进程、线程定义什么的就不多说了,这个东西百度就可以了,而且也是最基本的东西。稍微说一下区别吧。麻老师曾经这么总结过区别:线程是CPU任务调度的最小单位,进程是操作系统分配资源的最小单位。很精辟,但是也很懵。结合自己看过的资料,大约懂了一点:一段正在执行的程序就是一个进程,比如刚入门写的"Hello World"等;而线程是程序执行的最小单元,即一个进程可以拥有多个线程,各个线程之间共享程序的内存空间等等。举个例子,比如一个公司(操作系统)会有各种分厂(进程),工厂会有n条生产流水线(线程)。各个工厂之间是独立的,大家有各自的财务、厂长、生产资料等等,但是同一个工厂中各个流水线却共享工厂的财务、厂长、生产资料等等。然后董事会分配资源、制定计划是以工厂为单位。(例子貌似不是很恰当...水平有限,想不到好点的例子)。

二,如何实现多线程

java中实现多线程有三种方式,但是一般前两种用的比较多。
1.继承Thread类,重写run()方法

Thread本质是一个实现了Runnable接口的实例(Runnable接口后面会讲),代表的就是一个线程的实例。启动线程的的流程:首先通过Thread类的start()方法启动线程,这也是唯一的方法。start()方法将会启动一个新的线程,并执行run()方法,执行run方法中的代码。所以,我们一般会在run()方法中写入自己想要执行的代码。

示例代码:

public class Main {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.start();
    }
}

class MyThread extends Thread{  //创建一个线程
    @Override
    public void run() {
        System.out.println("hello");
    }
}

2.实现Runnable接口,并实现run()方法

主要步骤:

1)自定义类实现Runnable接口,实现run()方法

2)创建Thread对象,把实现Runnable接口的对象作为参数传入。

3)调用Thread的start()方法。

代码:

public class Main {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        Thread thread = new Thread(myThread);
        thread.start();
    }
}

class MyThread implements Runnable{  //创建一个线程
    @Override
    public void run() {
        System.out.println("hello");
    }
}
 

3.实现Callable接口,重写call()方法

Callable接口是Executor框架中的实现类。类似于Runnable接口,但是更加强大:

1)Callable接口在任务结束之后,可以返回一个返回值,Runnable则不可以。

2)Callable接口的call()方法可以跑出异常,但是Runnable接口的run()方法则不能抛出异常。

3)运行Callable接口可以拿到一个Future对象,Future对象表示异步计算的结果,提供了方法可以计算是否完成。因为多线程属于异步计算,前面的两种方法无法从别的线程得知返回情况。在这种方法们可以使用Future监视目标线程调用call()方法的情况,调用Future的get()方法以获取结果时,当前线程会被阻塞至call()方法结束返回结果。

代码:

import java.util.concurrent.*;

public class Main {
    public static void main(String[] args) {
        ExecutorService threadPool = Executors.newSingleThreadExecutor();
        //启动线程
        Future<String> future = threadPool.submit(new CallableTest());
        try{
            System.out.println("wait...");
            System.out.println(future.get());
            System.out.println("finish...");
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}

class CallableTest implements Callable<String>{

    @Override
    public String call() throws Exception {
        return "hello";
    }
}


总结:前两种方法,我们一般选择哪种方法?

第二种。看书中的介绍,主要是有两种原因:

:(两种方法实现功能类似)Thread类定义多个方法可以被重写,但是只有run()方法必须被重写。Runnable接口也可以做到。

二:(默认的约定)一般只有一个类被加强、修改的时候,才会被继承。如果没有必要重写Thread类的其他方法,则可以通过实现Runnable接口就可以实现。

因此一般选择第二种。

三:run()与start()区别:

通常调用start()方法,可以实现启动一个线程,并成为就绪态,但是并不是运行态。只是可以被JVM来调度。调度时,JVM调用run方法来完成实际的操作。因此,如果直接调用线程类的run方法,则变成一个普通的函数调用,依然是一个线程执行。如果调用start方法才能实现多线程。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值