[JAVA笔记]-基础-多线程-创建线程的四种方式

线程

创建线程的四种方式

一.继承Thread 类.

  • Thread 类本质上是实现了 Runnable 接口的一个实例,代表一个线程的实例。启动线程的 唯一方法就是通过 Thread 类的 start(实例方法。start()方法是一个 native 方法,它将启 动一个新线程,并执行run0方法。这种方式实现多线程很简单,通过自己创建的类直接extend Thread,并复写 run()方法,就可以启动新线程并执行自己定义的 run()方法.
  • 优点:代码简单。
  • 缺点:该类无法继承别的类.
public class Demo_Thread {
    public static void main(String[] args) {
        ThreadDemo thread1 = new ThreadDemo();
        thread1.setName("线程1");
        thread1.start();
        ThreadDemo thread2 = new ThreadDemo();
        thread2.setName("线程2");
        thread2.start();
    }
}
class ThreadDemo extends Thread{

    @Override
    public void run(){
        for (int i = 1;i<=10;i++){
            System.out.println(Thread.currentThread().getName() + ";" + i);
        }
    }
}

image.png

二.实现 Runnable 接口

  • Java 中的类属于单继承,如果自己的类已经 extends 另一个类,就无法直接 extends Thread, 但是一个类继承一个类同时,是可以实现多个接口的
  • 优点:继承其他类。统一实现该接口的实例可以共享资源。
  • 缺点:代码复杂.
  • 例:
public class Demo_Thread2 {
    public static void main(String[] args) {
        MyThread thread = new MyThread();
        Thread thread1 = new Thread(thread,"线程1");
        thread1.start();

        Thread thread2 = new Thread(thread,"线程2");
        thread2.start();
    }
}
class MyThread implements Runnable{

    @Override
    public void run() {
        for (int i = 1;i<=10;i++){
            System.out.println(Thread.currentThread().getName() + ";" + i);
        }
    }
}

image.png

三.实现 Callable 接口.

  • 实现 Runnable 和实现 Callable 接口的方式基本相同,不过 Callable 接口中的 call()方法有返回值,Runnable 接口中的 run()方法无返回值.
public class Demo_Thread3 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Callable<Object> oneCallable = new Tickets<Object>();
        //a.使用FutureTask类包装Callable对象,该FutureTask对象封装了Callable对象的Call方法的返回值
        FutureTask<Object> oneTask = new FutureTask<Object>(oneCallable);
        //b.创建Thread对象,参数为FutureTask对象
        Thread t = new Thread(oneTask,"线程1");
        //c.使用FutureTask对象作为Thread对象的target创建并启动线程
        t.start();
        //d.调用FutureTask对象的get()方法获取子线程执行完毕后的结果
        System.out.println(oneTask.get());
    }
}
class Tickets<String> implements  Callable<Object> {

    @Override
    public Object call() throws Exception {
        for (int i=1;i<=10;i++){
            System.out.println(i);
        }
        return Thread.currentThread().getName()+"线程执行完毕!";
    }
}

image.png

四.线程池方式

  • 线程池,其实就是一个容纳多个线程的容器,其中的线程可以重复使用,省去了频繁 创建线程对象的操作 因为反复创建线程是非常消耗资源的
  • 优点:实现自动化装配,易于管理,循环利用资源。
  • Executors类: 提供了 系列工厂方法用于创建线程池, 返回的线程池都实现了ExecutorService接口。
    • public static ExecutorService newFixedThreadPool(int nThreads): 创建固定数日线程的线程池,
    • public static ExecutorService newSingleThreadExecutor(): 创建一个单线程化的Executor
    • ExecutorService提供了submit()方法,传递一个Callable,或Runnable,将线程放到池子里,并执行. 优点:实现自动化装配, 易于管理,循环利用资源
public class Demo_Thread4 {
    public static void main(String[] args){
        //创建一个指定数目线程的线程池
        ExecutorService pool = Executors.newFixedThreadPool(2);
        //将线程放到池子里,并执行
        Future<?> submit = pool.submit(new RunnableThread());//有返回值的
        pool.submit(new RunnableThread());
        //关闭线程池
        pool.shutdown();
    }
}
class RunnableThread implements Runnable{
    @Override
    public void run(){
        for (int i = 1; i <= 10; i++) {
        System.out.println(Thread.currentThread().getName()+":"+ i);
        }
    }
}

image.png

扩展.Lock 接口比 synchronized 块的优势是什么

能够显示地获取和释放锁,锁的运用更灵活

  • Lock 中的方法
  • lock()方法:加锁+
  • unlock()方法:释放锁

可以方便地实现公平锁。

  • 公平锁:表示线程获取锁的顺序是按照线程加锁的顺序来的进行分配的,即先来先得 先进先出顺序。

  • 非公平锁:一种获取锁的抢占机制 是随机拿到锁的,和公平锁不一样的是先来的不 一定先拿到锁,这个方式可能造成某些线程- 直拿不到锁,结果就是不公平的。

  • 例:

    • 你需要实现一个高效的缓存,它允许多个用户读, 但只允许一个用户写,以此来保持它的完整性,你会怎样去实现它? 整体上来说 Lock 是 synchronized 的扩展版 Lock 提供了无条件的、可轮询的(tryLock 方法)、定时的(tryLock 带参方法)、 可中断的(lockInterruptibly)、可多条件队列的(newCondition 方法)锁操作。另外 Lock 的实现类基本都支持非公平锁(默认)和公平锁,synchronized只支持非公平锁 当然,在大部分情况下,非公平锁是可提高效率的.

应用场景.

为什么要学习多线程.

  • 吞吐量:举例,你做WEB容器帮你做了多线程,但是他只能帮你做请求层面的。简单的说,可能就是一个请求一个线程。或多个请求一个线程。如果是单线程,那同时只能处理一个用户的请求。
  • 伸缩性:也就是说,你可以通过增加 CPU 核数来提升性能。如果是单线程,那程序执行到死也就利用了单核,肯定没办法通过增加 CPU 核数来提升性能,如果是多线程,就可以提高CPU的使用性能;
  • 举例:卖票案例,一个线程相当于 个窗口,多线程相当于多个窗口卖票,多个线程可以大大提高效率(下一篇文章会详细说明)
更新时间:2019-10-18 14:41:49

本文由 Alicyu 创作,如果您觉得本文不错,请随意赞赏
采用 知识共享署名4.0 国际许可协议进行许可
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名
原文链接:https://www.alicyu.com/archives/thread
最后更新:2019-10-18 14:41:49

Your browser is out of date!

Update your browser to view this website correctly. Update my browser now

×