2019年java中高级java面试题(七)多线程

1、 现在有T1、T2、T3三个线程,你怎样保证T2在T1执行完后执行,T3在T2执行完后执行?

        Thread t1 = new Thread(() -> System.out.println("t1执行"));
        Thread t2 = new Thread(() -> System.out.println("t2执行"));
        Thread t3 = new Thread(() -> System.out.println("t3执行"));
        try {
            // t1先启动
            t1.start();
            t1.join();
            // t2
            t2.start();
            t2.join();
            // t3
            t3.start();
            t3.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


上述主要是利用join方法  等待该线程终止。主线程等待t1执行完     再开启t2线程,等待t2线程执行完再执行线程t3

join方法源码分析

 public final synchronized void join(long millis)throws InterruptedException {
        long base = System.currentTimeMillis();
        long now = 0;
 
        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }
 
        if (millis == 0) {
            while (isAlive()) {
                wait(0);
            }
        } else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }


2、 什么是线程


线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。

3、 线程和进程有什么区别?


线程是进程的子集,一个进程可以有很多线程,每条线程并行执行不同的任务。不同的进程使用不同的内存空间,而所有的线程共享一片相同的内存空间

4、 Java中Runnable和Callable有什么不同?


Runnable和Callable都代表那些要在不同的线程中执行的任务。Runnable从JDK1.0开始就有了,Callable是在JDK1.5增加的。它们的主要区别是

(1)Callable规定的方法是call(),Runnable规定的方法是run()。其中Runnable可以提交给Thread来包装下,直接启动一个线程来执行,而Callable则一般都是提交给ExecuteService来执行。

(2)Callable的任务执行后可返回值,而Runnable的任务是不能返回值得

(3)call方法可以抛出异常,run方法不可以

(4)运行Callable任务可以拿到一个Future对象,c表示异步计算的结果。

5、Java中CountDownLatch 和CyclicBarrier 有什么不同?

CountDownLatch类位于java.util.concurrent包下,利用它可以实现类似计数器的功能,一个线程(或者多个), 等待另外N个线程完成某个事情之后才能执行

CyclicBarrier通过它可以实现让一组线程等待至某个状态之后再全部同时执行,CyclicBarrier可以被重用
 

CountDownLatch

CyclicBarrier

减计数方式

加计数方式

计算为0时释放所有等待的线程

计数达到指定值时释放所有等待线程

计数为0时,无法重置

计数达到指定值时,计数置为0重新开始

调用countDown()方法计数减一,调用await()方法只进行阻塞,对计数没任何影响

调用await()方法计数加1,若加1后的值不等于构造方法的值,则线程阻塞

不可重复利用

可重复利用

6、线程运行的多种状态

 

  •          创建  new Thread类或者其子类对象。
  •          运行 start().  具备者CPU的执行资格和CPU的执行权。
  •          冻结 释放了CPU的执行资格和CPU的执行权。比如执行到sleep(time)  wait() 导致线程冻结。
  •          临时阻塞状态: 具备者CPU的执行资格,不具备CPU的执行权。
  •         消亡:线程结束。run方法结束 

7、Java中的volatile 变量是什么?


volatile是一个特殊的修饰符,只有成员变量才能使用它。 当一个共享变量被volatile修饰时,它会保证修改的值会立即被更新到主存,当有其他线程需要读取时,它会去内存中读取新值。

volatile特性一:内存可见性,即线程A对volatile变量的修改,其他线程获取的volatile变量都是最新的。

volatile特性二:可以禁止指令重排序

volatile关键字保证了操作的可见性,但是不能保证对变量的操作是原子性。

8、 volatile的原理和实现机制


加入volatile关键字时,生成的汇编代码会多出一个lock前缀指令

  lock前缀指令实际上相当于一个内存屏障(也成内存栅栏),内存屏障会提供3个功能:

  1)它确保指令重排序时不会把其后面的指令排到内存屏障之前的位置,也不会把前面的指令排到内存屏障的后面;即在执行到内存屏障这句指令时,在它前面的操作已经全部完成;

  2)它会强制将对缓存的修改操作立即写入主存;

  3)如果是写操作,它会导致其他CPU中对应的缓存行无效。

9、 使用volatile关键字的场景


1、状态标记量

volatile boolean flag= false;
 
// 线程1
context = loadContext();
flag= true;
 
// 线程2
while(!flag) {
    sleep();
}
doSomethingWithConfig(context);


2、双重检查

所谓双重检查加锁机制,指的是:并不是每次进入getInstance方法都需要同步,而是先不同步,进入方法过后,先检查实例是否存在,如果不存在才进入下面的同步块,这是第一重检查。进入同步块过后,再次检查实例是否存在,如果不存在,就在同步的情况下创建一个实例,这是第二重检查。这样一来,就只需要同步一次了,从而减少了多次在同步情况下进行判断所浪费的时间。 

public class Singleton {
    private volatile static Singleton instance = null;
 
    private Singleton() {}
 
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {// 1
                if (instance == null) {// 2
                    instance = new Singleton();// 3
                }
            }
        }
        return instance;
    }
}


3、独立观察(independent observation)

安全使用 volatile 的另一种简单模式是:定期 “发布” 观察结果供程序内部使用。例如,假设有一种环境传感器能够感觉环境温度。一个后台线程可能会每隔几秒读取一次该传感器,并更新包含当前文档的 volatile 变

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值