多线程的实现方式

四种方式实现多线程

  1. 继承 Thread 类创建线程

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

    public class MyThread extends OtherClass implements Runnable {  
        public void run() {  
            System.out.println("MyThread.run()");  
        }  
    }
    
    MyThread myThread = new MyThread();  
    Thread thread = new Thread(myThread);  
    thread.start();
    
  3. 实现Callable接口通过FutureTask包装器来创建Thread线程

    public class SomeCallable<V> extends OtherClass implements Callable<V> {
        @Override
        public V call() throws Exception {
            // TODO Auto-generated method stub
            return null;
        }
    }
    
    Callable<V> oneCallable = new SomeCallable<V>();   
    FutureTask<V> oneTask = new FutureTask<V>(oneCallable);   
    Thread oneThread = new Thread(oneTask);   
    oneThread.start();
    
  4. 使用ExecutorService、Callable、Future实现有返回结果的线程

    import java.util.concurrent.*;  
    import java.util.Date;  
    import java.util.List;  
    import java.util.ArrayList;  
    
    public class Test {  
        public static void main(String[] args) throws ExecutionException, InterruptedException {  
            System.out.println("----程序开始运行----");  
            Date date1 = new Date();  
    
            int taskSize = 5;  
            ExecutorService pool = Executors.newFixedThreadPool(taskSize);  
            List <Future> list = new ArrayList <Future>();  
    
            for (int i = 0; i < taskSize; i++) {  
                Callable c = new MyCallable(i + " ");  
                Future f = pool.submit(c);  
                list.add(f);  
            }  
    
            pool.shutdown();  
    
            for (Future f : list) {  
                System.out.println(">>>" + f.get().toString());  
            }  
    
            Date date2 = new Date();  
            System.out.println("----程序结束运行----,程序运行时间【" + (date2.getTime() - date1.getTime()) + "毫秒】");  
        }  
    }  
    
    class MyCallable implements Callable <Object> {  
        private String taskNum;  
    
        MyCallable(String taskNum) {  
            this.taskNum = taskNum;  
        }  
    
        public Object call() throws Exception {  
            System.out.println(">>>" + taskNum + "任务启动");  
            Date dateTmp1 = new Date();  
            Thread.sleep(1000);  
            Date dateTmp2 = new Date();  
            long time = dateTmp2.getTime() - dateTmp1.getTime();  
            System.out.println(">>>" + taskNum + "任务终止");  
            return taskNum + "任务返回运行结果, 当前任务时间【" + time + "毫秒】";  
        }  
    }
    

多线程相关知识

  1. Runnable 和 Callable 的区别?

    • 主要区别:

      • Runnable 接口 run 方法无返回值;
      • Callable 接口 call 方法有返回值,支持泛型。
    • 异常处理:

      • Runnable 接口 run 方法只能抛出运行时异常,且无法捕获处理;

      • Callable 接口 call 方法允许抛出异常,可以获取异常信息。

运行时异常通常是由程序逻辑错误引起的,例如除零操作、数组越界、空指针引用等。

换言之,Runable 比较保守,啥也没有。

  1. 如何启动一个新线程、调用 start 和 run 方法的区别?
    • 调用 run 方法不开启线程,仅是对象调用方法。
    • 调用 start 方法开启线程,并让 JVM 调用 run 方法在开启的线程中执行。调用 start 方法可以启动线程,并使得线程进入就绪状态,而 run 方法只是 thread 的一 个普通方法,还是在主线程中执行。
  2. 线程相关的基本方法?
    • wait:线程进入 waiting 状态,释放对象锁。
    • sleep:线程进入 TIMED-WATING 状态,不释放对象锁。
    • yield:线程让出 CPU 执行时间片。
    • join:等待其他线程终止。
    • interrupt:中断一个线程。
      • 不会直接停止线程的执行,而是设置了中断标志位。
    • notify:唤醒在此对象监视器上等待的单个线程。
    • notifyAll:唤醒在此对象监视器上等待的所有线程。
  3. wait() 和 sleep() 的区别?
    • 来自不同的类:wait() 来自 Object 类;sleep() 来自 Thread 类。
    • 关于锁的释放:wait() 在等待的过程中会释放锁;sleep() 在等待的过程中不会释放锁。
    • 使用的范围:wait() 必须在同步代码块中使用;sleep() 可以在任何地方使用。
      • 同步代码块:同步代码块通过关键字 synchronized 来定义,将一段代码包装在同步块中,以确保在同一时刻只有一个线程可以执行该代码块。
    • 是否需要捕获异常:wait() 不需要捕获异常;sleep() 需要捕获异常。
  4. 多线程原理
    • 多线程是通过并发的方式进行。在某个时间点上,CPU 只能执行一个程序,即同一时间只能运行一个进程。CPU 在多个进程之间切换执行,每个线程执行一段时间。
    • 多线程技术主要解决处理器单元内多个线程执行的问题,提高处理器单元的吞吐能力。

你可能感兴趣的:(面试,java)