zoukankan      html  css  js  c++  java
  • 线程(二)

    ● 创建线程有几种不同的方式?你喜欢哪一种?为什么?

    考察点:JAVA线程

    参考回答:

    有三种方式可以用来创建线程: 
    继承Thread类 
    实现Runnable接口 
    应用程序可以使用Executor框架来创建线程池 
    实现Runnable接口这种方式更受欢迎,因为这不需要继承Thread类。在应用设计中已经继承了别的对象的情况下,这需要多继承(而Java不支持多继承),只能实现接口。同时,线程池也是非常高效的,很容易实现和使用。

    ● 请解释一下Java多线程回调是什么意思?

    考察点:JAVA多线程

    参考回答:

    所谓回调,就是客户程序C调用服务程序S中的某个方法A,然后S又在某个时候反过来调用C中的某个方法B,对于C来说,这个B便叫做回调方法。

    ● 请列举一下启动线程有哪几种方式,之后再说明一下线程池的种类都有哪些?

    考察点:线程池

    参考回答:

    ①启动线程有如下三种方式:

    一、继承Thread类创建线程类

    (1)定义Thread类的子类,并重写该类的run方法,该run方法的方法体就代表了线程要完成的任务。因此把run()方法称为执行体。

    (2)创建Thread子类的实例,即创建了线程对象。

    (3)调用线程对象的start()方法来启动该线程。

    代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    package com.thread;
    public class FirstThreadTest extends Thread{
        int i = 0;
        //重写run方法,run方法的方法体就是现场执行体
        public void run()
        {
            for(;i<100;i++){
            System.out.println(getName()+"  "+i);
             
            }
        }
        public static void main(String[] args)
        {
            for(int i = 0;i< 100;i++)
            {
                System.out.println(Thread.currentThread().getName()+"  : "+i);
                if(i==20)
                {
                    new FirstThreadTest().start();
                    new FirstThreadTest().start();
                }
            }
        }
      
    }

    上述代码中Thread.currentThread()方法返回当前正在执行的线程对象。GetName()方法返回调用该方法的线程的名字。

    二、通过Runnable接口创建线程类

    (1)定义runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体。

    (2)创建 Runnable实现类的实例,并依此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象。

    (3)调用线程对象的start()方法来启动该线程。

    代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    package com.thread;
      
    public class RunnableThreadTest implements Runnable
    {
      
        private int i;
        public void run()
        {
            for(i = 0;i <100;i++)
            {
                System.out.println(Thread.currentThread().getName()+" "+i);
            }
        }
        public static void main(String[] args)
        {
            for(int i = 0;i < 100;i++)
            {
                System.out.println(Thread.currentThread().getName()+" "+i);
                if(i==20)
                {
                    RunnableThreadTest rtt = new RunnableThreadTest();
                    new Thread(rtt,"新线程1").start();
                    new Thread(rtt,"新线程2").start();
                }
            }
      
        }
      
    }

    三、通过Callable和Future创建线程

    (1)创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,并且有返回值。

    (2)创建Callable实现类的实例,使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。

    (3)使用FutureTask对象作为Thread对象的target创建并启动新线程。

    (4)调用FutureTask对象的get()方法来获得子线程执行结束后的返回值

    代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    package com.thread;
    import java.util.concurrent.Callable;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.FutureTask;
      
    public class CallableThreadTest implements Callable<Integer>
    {
      
        public static void main(String[] args)
        {
            CallableThreadTest ctt = new CallableThreadTest();
            FutureTask<Integer> ft = new FutureTask<>(ctt);
            for(int i = 0;i < 100;i++)
            {
                System.out.println(Thread.currentThread().getName()+" 的循环变量i的值"+i);
                if(i==20)
                {
                    new Thread(ft,"有返回值的线程").start();
                }
            }
            try
            {
                System.out.println("子线程的返回值:"+ft.get());
            catch (InterruptedException e)
            {
                e.printStackTrace();
            catch (ExecutionException e)
            {
                e.printStackTrace();
            }
      
        }
      
        @Override
        public Integer call() throws Exception
        {
            int i = 0;
            for(;i<100;i++)
            {
                System.out.println(Thread.currentThread().getName()+" "+i);
            }
            return i;
        }
      
    }

    ②线程池的种类有:

    Java通过Executors提供四种线程池,分别为:
    newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
    newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
    newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
    newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

    ● 请简要说明一下JAVA中cyclicbarrier和countdownlatch的区别分别是什么?

    考察点:线程

    参考回答:

    CountDownLatch和CyclicBarrier都能够实现线程之间的等待,只不过它们侧重点不同:

    CountDownLatch一般用于某个线程A等待若干个其他线程执行完任务之后,它才执行;

    而CyclicBarrier一般用于一组线程互相等待至某个状态,然后这一组线程再同时执行;

    另外,CountDownLatch是不能够重用的,而CyclicBarrier是可以重用的。

    ● 请说明一下线程池有什么优势?

    考察点:线程池

    参考回答:

    第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。

    第二:提高响应速度。当任务到达时,任务可以不需要等到线程创建就能执行。

    第三:提高线程的可管理性,线程是稀缺资源,如果无限制地创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一分配、调优和监控。

    ● 请回答一下Java中有几种线程池?并且详细描述一下线程池的实现过程

    考察点:线程池

    参考回答:

    1、newFixedThreadPool创建一个指定工作线程数量的线程池。每当提交一个任务就创建一个工作线程,如果工作线程数量达到线程池初始的最大数,则将提交的任务存入到池队列中。 
    2、newCachedThreadPool创建一个可缓存的线程池。这种类型的线程池特点是: 
    1).工作线程的创建数量几乎没有限制(其实也有限制的,数目为Interger. MAX_VALUE), 这样可灵活的往线程池中添加线程。 
    2).如果长时间没有往线程池中提交任务,即如果工作线程空闲了指定的时间(默认为1分钟),则该工作线程将自动终止。终止后,如果你又提交了新的任务,则线程池重新创建一个工作线程。 
    3、newSingleThreadExecutor创建一个单线程化的Executor,即只创建唯一的工作者线程来执行任务,如果这个线程异常结束,会有另一个取代它,保证顺序执行(我觉得这点是它的特色)。单工作线程最大的特点是可保证顺序地执行各个任务,并且在任意给定的时间不会有多个线程是活动的 。 
    4、newScheduleThreadPool创建一个定长的线程池,而且支持定时的以及周期性的任务执行,类似于Timer。(这种线程池原理暂还没完全了解透彻) 

    ● 请说明一下Java中都有哪些方式可以启动一个线程?

    考察点:线程

    参考回答:

    1. 继承自Thread类

    2. 实现Runnable接口

    3.即实现Runnable接口,也继承Thread类,并重写run方法

    ● 请列举一下创建线程的方法,并简要说明一下在这些方法中哪个方法更好,原因是什么?

    考察点:线程

    参考回答:

    需要从Java.lang.Thread类派生一个新的线程类,重载它的run()方法;

    实现Runnalbe接口,重载Runnalbe接口中的run()方法。

    实现Runnalbe接口更好,使用实现Runnable接口的方式创建的线程可以处理同一资源,从而实现资源的共享.

    ● 请简短说明一下你对AQS的理解。

    考察点:多线程

    参考回答:

    AQS其实就是一个可以给我们实现锁的框架
    内部实现的关键是:先进先出的队列、state状态
    定义了内部类ConditionObject
    拥有两种线程模式独占模式和共享模式。
    在LOCK包中的相关锁(常用的有ReentrantLock、 ReadWriteLock)都是基于AQS来构建,一般我们叫AQS为同步器。

    ● 请简述一下线程池的运行流程,使用参数以及方法策略等

    考察点:线程池

    参考回答:

    线程池主要就是指定线程池核心线程数大小,最大线程数,存储的队列,拒绝策略,空闲线程存活时长。当需要任务大于核心线程数时候,就开始把任务往存储任务的队列里,当存储队列满了的话,就开始增加线程池创建的线程数量,如果当线程数量也达到了最大,就开始执行拒绝策略,比如说记录日志,直接丢弃,或者丢弃最老的任务。

    ● 线程,进程,然后线程创建有很大开销,怎么优化?

    考察点:多线程

    参考回答:

    可以使用线程池。

    ● 请介绍一下什么是生产者消费者模式?

    考察点:线程

    参考回答:

    生产者消费者问题是线程模型中的经典问题:生产者和消费者在同一时间段内共用同一存储空间,生产者向空间里生产数据,而消费者取走数据。

    优点:支持并发、解耦。

    ● 请简述一下实现多线程同步的方法?

    考察点:多线程

    参考回答:

    可以使用synchronized、lock、volatile和ThreadLocal来实现同步。

    ● 如何在线程安全的情况下实现一个计数器?

    考察点:多线程

    参考回答:

    可以使用加锁,比如synchronized或者lock。也可以使用Concurrent包下的原子类。

    ● 多线程中的i++线程安全吗?请简述一下原因?

    考察点:多线程

    参考回答:

    不安全。i++不是原子性操作。i++分为读取i值,对i值加一,再赋值给i++,执行期中任何一步都是有可能被其他线程抢占的。

  • 相关阅读:
    CodeForces 347B Fixed Points (水题)
    CodeForces 347A Difference Row (水题)
    CodeForces 346A Alice and Bob (数学最大公约数)
    CodeForces 474C Captain Marmot (数学,旋转,暴力)
    CodeForces 474B Worms (水题,二分)
    CodeForces 474A Keyboard (水题)
    压力测试学习(一)
    算法学习(一)五个常用算法概念了解
    C#语言规范
    异常System.Threading.Thread.AbortInternal
  • 原文地址:https://www.cnblogs.com/sbclmy/p/10834880.html
Copyright © 2011-2022 走看看