并发基础一

http://www.importnew.com/12773.html

1.什么是线程安全

多个线程访问某个类,主调代码不需要额外的同步和协同,这个类就能表现出正确的行为,我们就成这个类是线程安全的。比如LinkedBlockingQueue使用Lock加锁保证任何;

2.什么是线程

线程是操作系统能够进行运算调度的最小单位(我的理解是计算机有几个核心就可以并行运行几个线程);

3.什么是竞态条件

在并发编程中由于各个线程不正确的执行时序(执行时间顺序)而导致的不正确的结果,叫做竞态条件(race condition)。最常见的竞态条件是“先检查后执行”操作,即通过一个可能失效的观察决定下一步执行的动作。 如下代码会在condition上产生竞态条件:

thread1:
synchronized(sharedMonitor){
    //setup condition for thread2
    sharedMonitor.notify();//等待sharedMonitor对象监视器的线程被唤醒;
}

thread2:
while(condition){
    //重要X:线程调度器可能再次切换线程;
    synchronized(sharedMonitor){
        sharedMonitor.wait();
    }
}

  • 正确的做法是在thread2中将while(condition)放进同步代码块;
4. 如何停止一个线程
  1. 通过使用volatile布尔变量退出run()方法的循环——所有线程公用此变量,而且对此变量的修改可以被立即被各个线程的run()方法感知;
  2. ExecutorService 类的 shutdownnow()方法;
5. 线程运行时发生异常会怎样

如果不捕获异常的话线程将会停止执行,并且将**异常信息和线程交给默认的UncaughtExceptionHandler未捕获异常处理器进行处理。当然可以实现该接口,并且通过方法设置线程对应的“未捕获异常处理器”。

6.线程间如何共享数据——也可以说是如何通信?
  1. 通过共享对象通信。比如生产者-消费者的例子中,WaitPerson线程和Chef线程通过Meal对象来通信;
  2. 通过BlockingQueue(并发数据结构)共享数据,比如生产者-队列-消费例子中。
7. notify()notifyAll()的区别

前者是唤醒一个等待调用该方法对象说的线程,后者是唤醒所有等待该锁的线程,然后让他们竞争锁。notify()用不好容易导致死锁。

8.interrupt、interrupted 、isInterrupted三个方法的区别
  • interrupt会将此对象线程的“中断标识”设置为true,标识此线程是可中断的;
  • interruptedisInterrupted都会返回中断标识状态,但是前者会清空中断状态;
9.为什么在循环中检查等待条件
while(condition)
    wait();

因为等待状态的线程可能收到错误的警报,这样更加严谨,是的满足条件的条件下在运行后续程序;

10.java中堆heap和栈stack的区别

java堆的

1. 目的是存放几乎所有的对象实例和数组;
2. 在虚拟机启动时创建,被所有线程所共享;
3. 堆内存没有空间完成实例分配且无法在扩展时,抛出OutOfMemoryError异常;

java栈的

1. 存放基本数据类型、对象的引用(、方法参数和栈调用);
2. 局部变量表所需的内存空间在编译期间完成分配。java栈是线程私有的,生命周期与线程相同;
3. 这个区域规定了两种异常:线程请求的栈深度超过虚拟机所允许的深度抛出StackOverflowError。如果动态扩展的虚拟机栈无法申请到足够的内存,则会抛出OutOfMemoryError异常;
11.怎样确保三个线程按照顺序执行

join()方法:当前线程等待调用此方法的线程对象结束后再执行。

1
       Thread b=new Thread(()-> {
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("thread_b finished");
        });
        Thread a=new Thread(()-> {
            try{
                b.join();
                System.out.println("thread_a wait thread_b 3 second and finished");
            }catch (Exception e){
                e.printStackTrace();
            }
        });

        a.start();
        b.start();
12.如果同步块内的线程抛出异常会发生什么

无论你的同步块是正常还是异常退出的,里面的线程都会释放锁;

13.wait() 和 sleep()方法有什么不同

wait()会释放锁。sleep()仅仅是释放CPU资源而不释放锁。

14. ReentrantLock中三个加锁方法的区别
  • tryLock能获得锁就返回true,不能就立即返回false,tryLock(long timeout,TimeUnit unit),可以增加时间限制,如果超过该时间段还没获得锁,返回false
  • lock能获得锁就返回true,不能的话一直等待获得锁;
  • lock和lockInterruptibly如果两个线程分别执行这两个方法,但此时中断这两个线程,前者不会抛出异常,而后者会抛出异常
15.停止线程:做标记,三方法抛异常清除,短方法清除

停止一个线程使用interrupt()方法
除非线程要中断本身。此操作是为当前线程做标识“可以停止”,而非真正的停止线程。

如果线程在调用wait()、join()、sleep()及其各种变参多态函数后,再调用interrupt()方法会清空其interurpted的状态,并抛出InterruptedException异常。

线程是否是“可停止状态”可以调用两个方法:

  1. boolean interrupted():会清除“可停止状态”,测试的是当前线程;

2.boolean isInterrupted():不会清除状态,测试的是Thread对象;

因此中断线程的正确姿势是:

void run(){
    while(!Thread.interrupt){
        //do work
    }
    
}


当对线程调用 thread.interrupt() 时,就会停止工作,线程中断。注意最外层的try代码块。

16. 关闭线程池
executor.shutdown();//任务队列中的任务仍然被执行完成
while(!executor.isTerminated()){};

return;


...
shutdownNow()会返回未执行完的任务。

17.wait(),wait(XX),sleep(XX),yield()和join()
  • wait():放弃锁和cup时间片,等待其他线程用notifyAll()唤醒;
  • wait(XX):调用notifyAll()或者到XX时间后开始争用锁对象;
  • sleep(XX): 不释放锁,指定时间内放弃cpu时间片;
  • yield():同sleep,但是可能释放cup时间片后立即又开始执行,但是cup时间片只会让给线程优先级不小于其的线程;
  • join()/join(XXX):通过wait()实现,释放锁;

posted on 2018-04-21 15:03  coderDu  阅读(100)  评论(0编辑  收藏  举报