关于面试:太牛了第一次看到有大佬把Java线程与进程的这么详细的我先收藏了

45次阅读

共计 4229 个字符,预计需要花费 11 分钟才能阅读完成。

线程与过程

概念

过程:过程指的是一段正在运行的程序
线程:一个程序运行中能够执行多个工作,工作就称之为线程。
过程能够有多个线程,各个线程之间共享程序的内存空间

为什么有了过程,还会呈现线程?

每个过程有本人独立的地址空间,多并发申请,为每一个申请创立一个过程,导致系统开销、用户申请效率低

区别

每个过程有用本人独有的变量,线程共享数据,线程之间的通信相比于过程之间的通信更加无效,更加容易
线程相比于过程创立 / 销毁开销 更小
过程是资源分配的最小单位,线程是 CPU 调度的最小单位
多过程程序更加强壮,多线程程序只有有一个线程挂掉,对其共享资源的其余线程也回产生影响
如果谋求速度,谋求零碎稳固抉择线程;如果频繁的创立和销毁,抉择线程;

线程的创立

说完线程的基本知识,那么久要谈谈在利用中,咱们应该如何创立线程,理论利用中创立线程次要有以下四种办法,如下:

办法一:继承 Thread 类,重写 run()办法


class  MyThread extends  Thread{
    @Override
    public void run() {while(true){System.out.println("eat food");
        }
    }
}
public class TestDemo1 {public static void main(String[] args) {
        // 边吃饭边看电视
        // 创立子线程对象
        Thread thread = new MyThread();
        // 启动吃饭的 thread
         thread.run();
         //main 线程
        while(true){System.out.println("watch Tv");
        }
    }
  }

办法二:实现 Runable 接口

class  MyRunnable implements  Runnable{
    @Override
    public void run() {while(true){System.out.println("eat food");
        }
    }
}
public class TestDemo1 {public static void main(String[] args) {// 实现 runnable 接口 创立子线程  创立子线程对象        Thread thread = new Thread(new MyRunnable());    
    thread.start();}
  }

办法三:匿名线程 应用匿名外部类

  // 匿名外部类   创立线程
            new Thread(){
                @Override
                public void run() {System.out.println("thread 0");
                }
            }.start();

办法四:实现 Callable 接口,重写 call()办法

利用 Callable 创立时,步骤较为简单,具体如下:
a. 创立 Callable 接口的实现类,重写 call 办法
b. 创立 Callable 实现类的实例,应用 FutureTask 包装该实例
c. 将 FutureTask 实例作为参数创立线程对象
d. 启动该线程
e. 调用 FutureTask 的 get 办法获取子线程的执行后果

class MyCallable implements Callable<Integer>{

    @Override
    public Integer call() throws Exception {
        int sum = 0;
        for(int i=0; i<10000; i++){sum += i;}
        return sum;
    }
}
public class TestDemo1 {public static void main(String[] args) {
     // 创立 Callable 接口的实现类    重写 call 办法
        // 创立 Callable 实现类的实例
        Callable<Integer> callableTask = new MyCallable();
        // 应用 FutureTask 包装实例
        FutureTask<Integer> task = new FutureTask<>(callableTask);
        //Future 实例作为参数创立线程对象
        Thread thread = new Thread(task);
        // 启动该线程
        thread.start();
        // 调用 FutureTask 的 get 办法获取子线程的执行后果
        try {Integer integer = task.get();
            System.out.println("result"+integer);
        } catch (InterruptedException e) {e.printStackTrace();
        } catch (ExecutionException e) {e.printStackTrace();
        }

可能有人会思考,这里同样应用 Runable 和 Callable 接口来创立线程,那么这两者各有什么不同呢?能想到这,堪称是很用心啦,这也是这里的一个面试考点呐!!!
Runable 接口和 Callable 接口的区别?

这里就简略说一下两者的区别,然而仅仅独自比拟两个接口的区别实际意义并不大,并且也不是很全面,之后会
具体的剖析两个接口的区别,在更深层次下来了解两个接口。大家持续关注吖!

线程的生命周期及罕用办法解析

生命周期

线程的生命周期次要包含以下六种状态:新建状态、就绪状态、阻塞状态、期待状态、睡眠状态、终止状态。

  1、new():新建状态  new 关键字创立一个线程对象,它并不是出于执行状态 并未执行 START 办法启动线程
  2、runnable():就绪状态   期待被执行  线程对象调用 START 办法,才是 JVM 中真正创立了一个线程,创立好的线程并不是一经启动,就会立刻执行。该状态的所有线程会位于就绪线程池中,期待以后操作系统的资源,例如 CPU,取得 CPU 的使用权。3、blocked(): 阻塞状态 期待一个监视器锁进入同步代码块或者同步办法,代码块和办法指某一时刻
  只可能有一个线程去执行,其余线程只能期待。4、Waiting(): 期待状态  Object.wait()/Thread.join()/LockSupport.park() 都会使得以后从 Runnable
  转换为 Waiting 状态    调用 waiting()  会开释 monitor Lock
  5、TimeWaiting(): 睡眠状态    
   调用 Object.wait(long miles)/Thread.sleep(long miles)/LockSupport.parkNano()/LockSupport.parkUntile()
  6、Terminated():终止状态  是一个线程的最终状态  线程如果进入此状态,意味着该线程完结。

简略理解线程的生命周期之后,那咱们持续学习线程六状态之间的转换:

罕用办法解析

1) start()

启动一个线程,将线程增加到线程组中,线程状态会从 New 状态转换到 Runnable 状态,而后获取 CPU 之后进入 Running 状态执行 run();

2)sleep()

静态方法,存在两个重载函数

 public static native void sleep(long millis)
 public static void sleep(long millis, int nanos)

作用:sleep()办法使得以后线程进入睡眠状态并指定休眠工夫,暂停执行;
sleep()办法不会开释 Monitor Lock 使用权;
JDK1.5 之后,引入枚举类 TimeUnit,其对 sleep 进行封装 间接应用从而省去工夫换算的步骤,不必将工夫转为 ms, 更加的方便使用。

3)yield()

public static native void yield();

作用:揭示 CPU 调度器,我以后的线程违心放弃以后的 CPU 资源 (属于启发式办法), 如果以后 CPU 资源不缓和,会疏忽这种揭示。
yield() 办法不会开释 Monitor Lock 使用权;

4)join()

join() 始终期待
join(long millis) 期待指定毫秒数
join(long millis, int nanos) 期待指定毫秒数

含意:在线程 B 中 join 某个线程 A,会使得 B 线程进入期待,直到线程 A 完结生命周期,或者达到给定的工夫,在这给定工夫期间线程 B 会处于期待状态.

5)wait()

调用某个对象的 wait()办法能够让以后线程阻塞

6)notify()

调用以后对象 notify/notifyAll 才可能唤醒这个对象所在的线程。

7)notifyAll()

将锁对象期待池中所有线程挪动到锁标记期待池中。
留神:应用这三个办法须要让以后线程领有以后对象的 monitor lock

8)线程中断办法

每个 Java 线程都会有一个中断状态位,程序能够检测这个中断状态位判读线程是否执行完结。有以下三种办法:
interrupt()
public void interrupt() 由线程对象调用,将中断地位置为 true

public void interrupt();

如下办法可能使得以后线程进入阻塞状态,调用 interrupt 办法能够打断阻塞,因而这种办法被称之为可中断办法

Object.wait()/wait(long)
Thread.sleep(long)/TimUnit.XXX.sleep(long)
Thread.join()/Thread.join(long)

如果一个线程被 interrupt, 设置 interrupt flag;如果以后线程正在执行可中断办法,调用 interrupt 办法,反而导致 interrupt flag 被革除.

isInterrupted

public boolean isInterrupted();

实例办法,判断以后线程的中断状态位是否为 true, 判断过程是否被中断。

interrupted()

public static boolean interrupted();

静态方法,调用 interrupted 会擦除中断状态位的标识,判断过程是否被中断

interrupted 和 isInterrupted 办法的区别:

1)interrupted()是静态方法,isInterrupted()是实例办法;
2)interrupted()会清空线程中断状态,isInterrupted()不会清空线程中断状态。

最初

欢送关注公众号:前程有光,支付一线大厂 Java 面试题总结 + 各知识点学习思维导 + 一份 300 页 pdf 文档的 Java 外围知识点总结!这些材料的内容都是面试时面试官必问的知识点,篇章包含了很多知识点,其中包含了有基础知识、Java 汇合、JVM、多线程并发、spring 原理、微服务、Netty 与 RPC、Kafka、日记、设计模式、Java 算法、数据库、Zookeeper、分布式缓存、数据结构等等。

正文完
 0