java多线程并发(一)-- 相关基础知识

  java多线程的知识是java程序员都应该掌握的技能,目前我接触的项目上用的不多,花点时间熟悉熟悉。

一、基础知识

  1、什么是进程?

  进程是具有一定独立功能的正在运行过程中的程序,是操作系统进行资源分配的最小单位,有程序、数据、进程控制块组成。进程内部有多个线程,这多个线程会共享资源。 

  2、什么是线程? 

  线程有时称为轻量级进程,是CPU调度的最小单位,依赖于进程存在。线程自己不拥有系统资源,与同属于同一进程下的线程共享系统资源。

  3、什么是并行?

  并行(parallel):同一时刻,有多条指令在多个处理器上同时执行。所以无论从微观还是从宏观来看,二者都是一起执行的。

  4、什么是并发?

  并发(concurrency):同一时刻只能有一条指令执行,但多个进程指令被快速的轮换执行,使得在宏观上具有多个进程同时执行的效果,但在微观上并不是同时执行的,只是把时间分成若干段,使多个进程快速交替的执行。

  

  5、多高并发优缺点?

  优点:充分利用系统资源、加快用户响应时间、程序模块化、异步化;

  缺点:线程共享资源,存在冲突,容易导致死锁。

二、java新启线程的三种方式

  1、继承Thread 类,重写run方法:

class UseThread extends Thread{
    @Override
    public void run() {
        super.run();
        System.out.println("[" + Thread.currentThread().getName() + "]已启动!");
    }
}

public class Test {
    public static void main(String[] args){
        Thread thread = new UseThread();
        thread.setName("继承Thread的线程");
        thread.start();
    }
}

  2、实现Runable接口,实现run方法(或者内部类的形式)

class UseRunable implements Runnable{
    @Override
    public void run() {
        System.out.println("[" + Thread.currentThread().getName() + "]已启动!");
    }
}

public class Test {
    public static void main(String[] args){
        Thread thread = new Thread(new UseRunable());
        thread.setName("实现Runable接口的线程");
        thread.start();
    }
} 
Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("哈哈哈哈");
            }
        });

  3、实现Callable接口,实现call方法

class UseCallable implements Callable<String>{
    @Override
    public String call() throws Exception {
        System.out.println("[" + Thread.currentThread().getName() + "]已启动!");
        return "12345";
    }
}

public class Test {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask futureTask = new FutureTask(new UseCallable());
        Thread thread = new Thread(futureTask);
        thread.setName("实现Callable接口的线程");
        thread.start();
        System.out.println("call()方法返回的结果:" + futureTask.get());
    }
}

  Runable与Callable的区别:

  1. Runable的执行方法是run(),而Callable的执行方法是call();
  2. Runable没有返回结果,Callable支持泛型方式的返回结果,通过和Futrue/FutureTask配合可以用来获取异步执行的结果(FutureTask实际上实现了Runable接口,本质上是将Callable转换为Runable);
    public class FutureTask<V> implements RunnableFuture<V> {
        ...
    };
    public interface RunnableFuture<V> extends Runnable, Future<V> {
      ... }
  3. Callable的call()可以向上抛出异常,而Runable的run()不能抛出异常,异常只能内部消化(因为Runable中的run()声明的抽象方法没有抛出异常);
    @FunctionalInterface
    public interface Runnable {
        public abstract void run();
    }
    
    @FunctionalInterface
    public interface Callable<V> {
        V call() throws Exception;
    }

    注: Callable执行返回结果需要通过Future.get()获取,该方法会阻塞主线程直到返回结果,而不调用则不会阻塞。

  正常见到的线程实现方式就是这三种,实际还有第四种!!!

  4、使用线程池

  

public class Test {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        int poolSize = 5;
        ExecutorService executorService = Executors.newFixedThreadPool(poolSize);
        List<Future<String>> futureList = new ArrayList<>();
        for (int i=0;i<poolSize;i++){
            int finalI = i;
            Future<String> future = executorService.submit(new Callable<String>() {
                @Override
                public String call() throws Exception {
                    System.out.println("[" + finalI + "号线程]已执行!");
                    return "" + finalI + "号线程";
                }
            });
            futureList.add(future);
        }

        for (Future future : futureList){
            System.out.println("返回结果:" + future.get());
        }
    }
}

  当然,上面线程池的实现方式本质上还是使用的的Callable,当然也可以使用Runable。

  一般是推荐使用Runable的方式,java不能多继承,接口的方式利于扩展。

   

猜你喜欢

转载自www.cnblogs.com/guaniu2750/p/12330729.html