java多线程的问题---面试必备@Deprecate

简介: java多线程的问题---面试必备@Deprecate

1、什么是线程?

线程是指程序在执行过程中,能够执行程序代码的一个执行单元。

4种状态:运行、就绪、挂起和结束

线程是程序执行的最小单元,一个进程可以拥有多个线程,各个线程之间共享程序的内存空间(代码段、数据段和堆空间)以及一些进程级的资源,但是各个线程拥有自己的栈空间。


2、为什么使用多线程?

多线程可以减少程序的响应时间。可以把耗时的线程分配到一个单独的线程去执行

与进程相比,线程的创建和切换开销更小。运行于同一进程内的线程共享代码段、数据段,线程的启动或切换的开销比进程要少很多。

多cpu或多核的计算机本身就具有执行多线程的能力,如果使用单个线程,将无法重复利用计算机资源


3、同步和异步?

多线程的环境中,经常碰见数据的共享问题,当多个线程需要访问同一个资源时,他们需要一某种顺序来确保该资源在某个时刻只能被一个线程使用。

实现同步操作,必须要获得每一个线程对象的锁。以保证同一时刻只有一个线程能够进入临界区(访问互斥资源的代码块),并且在这个锁被释放之前,其他线程就不能再进入临界区。关键字:synchronized。以很大的系统开销为代价。

实现同步的方式:

1)同步代码块,

synchronized(任意对象){线程要操作的共享数据}

2)同步方法,

推荐public synchronized void method(){

可能产生线程安全问题的代码}

wait()方法与notify()方法:在synchronized代码被执行期间,线程可以调用对象的wait()方法,释放对象锁,进入等待状态,并且可以调用notify()方法或notifyAll()方法通知正在等待的其他线程。

notify()方法仅唤醒一个线程并允许它去获得锁,notifyAll()方法唤醒所有的等待这个对象的线程并允许他们去获得锁。

JDK1.5新增Lock接口(java.util.concurrent.locks)以及他的实现类ReetrantLock(重入锁),用于实现多线程的同步, lock实现了比使用synchronized方法和语句可获得更广泛的锁定操作。

void lock() //以阻塞的方式获取锁

tryLock() //以非阻塞的方式获取锁

tryLock(long timeout,TimeUnit unit) //如果获取了锁,立即返回true,否则会等待参数给定的时间单元,

lockInterruptibly() //如果获取了锁,立即返回true,当前线程处于休眠状态,直至获得锁,他与lock()方法的区别是如果lock()方法获取不到锁,会一直处于阻塞状态。

void unlock() //释放锁

异步与非阻塞类似,每个线程包含了运行时自身所需要的数据或方法,因此,在进行输入输出处理时,不必关心其他线程的状态或行为。


4、如何实现java多线程?

三种方法(1)继承Thread类,重写run方法。

启动线程的唯一方法是通过Thread类的start()方法。

(2)实现Runnable接口,并实现该接口的run()方法 推荐

步骤:自定义类并实现runnable接口,实现run方法;创建Thread对象,用实现Runnable接口的对象作为参数实例化该Thread对象;调用Thread的start方法。

(3)实现callable接口,重写call()方法 callable接口实际上是属于Executor框架中的功能类,提供了比Runnable更强大的功能,callable可以在任务结束后提供一个返回值,runnable无法提供这个功能,callable中的call()方法可以抛出异常,Runnable的run方法不能抛出异常;运行callable可以拿到一个Future对象,future对象表示异步计算的结果。

声明线程池:ExecutorService threadPool = Executors.newSingleThreadExecutor();

池中添加线程:Future<String> future =threadPool.submit(new CallableTest());

try{

syso("wait thread to finish");

syso(future.get());//等待线程结束,并获取返回结果

}


5、sleep()和wait()方法区别?

sleep()和wait()都是使线程暂停执行一段时间的方法

区别 1)原理不同 sleep方法是Thread类的静态方法,是线程用来控制自身流程的,他会使此线程暂停一段时间,机会让给其他线程,时间到后,线程会自行“苏醒” wait方法是object类的方法,用于线程间的通信,这个方法会使当前拥有该对象锁的进程等待,直到其他线程调用notify()方法时才醒来。

2)对锁的处理机制不同。 sleep方法只是让线程暂停,不涉及线程间的通信,因此,调用sleep()方法并不会释放锁,而wait()不同,线程会释放掉他占用的锁,从而使线程所在的对象中的其他synchronized数据可以被别的线程使用。

3)使用区域不同。wait必须放在同步控制方法或同步语句块中使用,而sleep()方法则可以放在任何地方使用。 推荐使用wait()方法。

引申:sleep方法和yield方法的区别?

1)sleep给其他线程运行时不考虑优先级,yield会给同优先级或更高优先级的线程运行机会

2)执行sleep后转入阻塞状态,而yield方法只是使当前线程重新回到可执行状态,所以有可能在进入到可执行状态后马上又被执行。

3)sleep声明抛出InterruptedException,而yield方法没有声明任何异常。

4)sleep方法比yield方法(跟操作系统有关)具有更好的可移植性。


6、终止线程的方法?

1)Thread.stop(),终止线程时,他会释放已经锁定的所有监事资源。会导致程序执行的不确定性

2)suspend(),这个方法容易产生死锁,调用suspend()方法时不会释放锁,互斥资源的竞争会导致死锁的发生。

java语言已经不推荐这两种方法,那么如何终止线程?让线程自行结束进入dead状态。可以设置一个flag来控制循环是否执行,通过这种方法来让线程离开run()方法从而终止线程,如下所示:

public class MyThread implements Runnable{
    private volatile Boolean flag;
    public void stop(){
        flag = false;
    }
    public void run(){
        while(flag)
        ;//do something
    }
}

问题:当线程处于非运行状态时(sleep方法被调用或当wait方法被调用或I/O阻塞时),这个方法不管用。

此时可以用interrupt来打破阻塞的情况,当interrupt()被调用时,会抛出InterruptedException异常,可以通过在run()方法中捕获这个异常来让线程安全退出。

public class MyThread{
    public static void main(String[] args){
    Thread thread = new Thread(new Runable(){
        public void run(){
            syso("thread go to sleep");
            try{
            //用休眠来模拟线程被阻塞            
                Thread.sleep(5000);
                syso("thread finish");
            }catch(InterruptedException e){
                syso("thread is interrupted");
                }
        }
    });
    thread.start();
    thread.interrupt();
    }
}

如果程序因为IO而停滞,基本上要等到IO完成才能离开这个状态,无法使用Interrupte()方法使程序离开run()方法。思路:触发一个异常,而这个异常与所使用的I/O相关。


7、synchronized与lock的差异?  常常问倒,例如今年的网易面试题

这两锁机制来实现对某个共享资源的同步:synchronized使用Object对象本身的notify,wait,notifyAll调度机制,而lock可以使用condition进行线程间的调度。

区别 1)用法不一样,synchronized在需要被同步的对象中加入。Lock需要显示地指定起始位置和终止位置,synchronized是托管给JVM执行的,Lock的锁定是通过代码实现的。

2)性能不一样

jdk5中增加Lock接口的实现类ReentrantLock,他不仅拥有和Synchronized相同的并发性和内存语义,还多了锁投票,定时锁,等候和中断锁等。在资源竞争不是很激烈时,Synchronized的性能要优于ReentrantLock,但竞争激烈时,Synchronized的性能下降得很快,但ReentrantLock的性能基本保持不变。

3)锁机制不一样

Synchronized获取和释放锁的方式都是在块结构中,当获取多个锁时必须以相反的顺序释放,并且是自动解锁,不会因为出了异常导致锁没有被释放从而引发死锁;而Lock则需要开发人员手动释放,并且必须在finally块中释放,Lock还提供了更强大的功能,他的tyLock()方法可以采用非阻塞的方式去获取锁。

笔试题:当一个线程进入一个对象的一个synchronized()方法后,其他线程是否可进入此对象的其他方法?

当一个线程进入一个对象的一个synchronized()方法后,其他线程是否可进入此对象的其他方法取决于方法本身,如果该方法是非synchronized()方法,那么是可以访问的。如下所示:

如果其他方法是静态方法(使用static修饰的方法),他用的同步锁是当前类的字节码,与非静态的方法不能同步(因为非静态的方法用的是this),因此,静态方法可以被调用。


8、什么是守护线程?

java提供了两种线程:守护线程和用户线程

守护线程称为“服务进程”“后台线程”,指的是在程序运行时在后台提供一种通用服务的线程,这种线程并不属于程序中不可或缺的部分。

守护线程优先级较低,将一个用户线程设置为守护线程的方法就是在调用start()方法启动线程之前调用对象的setDaemon(true)方法,若将以上参数设置为false,则表示的是用户进程模式。当一个守护线程中产生了其他线程,那么这些新产生的线程默认还是守护线程。

守护线程的一个典型的例子是:垃圾回收器。只要JVM启动,它始终在运行,实时监控和管理系统中可以被回收的资源。


9、join()方法的作用是什么?

join方法的作用是让调用该方法的线程在执行完run()方法后,再执行join方法后面的代码。简单点说,就是将两个线程合并,用于实现同步功能。

祝大家面试顺利,找到理想的工作,一起加油!

10、线程的一些方法wait,notify,condition await() signal()

我:先从方法属于什么类,有什么作用,一般什么场景用,有什么区别,甚至可以说下替代方案(表明自己的一个技术广度)

待整理

相关文章
|
2天前
|
安全 Java API
java如何请求接口然后终止某个线程
通过本文的介绍,您应该能够理解如何在Java中请求接口并根据返回结果终止某个线程。合理使用标志位或 `interrupt`方法可以确保线程的安全终止,而处理好网络请求中的各种异常情况,可以提高程序的稳定性和可靠性。
24 6
|
17天前
|
设计模式 Java 开发者
Java多线程编程的陷阱与解决方案####
本文深入探讨了Java多线程编程中常见的问题及其解决策略。通过分析竞态条件、死锁、活锁等典型场景,并结合代码示例和实用技巧,帮助开发者有效避免这些陷阱,提升并发程序的稳定性和性能。 ####
|
15天前
|
存储 监控 小程序
Java中的线程池优化实践####
本文深入探讨了Java中线程池的工作原理,分析了常见的线程池类型及其适用场景,并通过实际案例展示了如何根据应用需求进行线程池的优化配置。文章首先介绍了线程池的基本概念和核心参数,随后详细阐述了几种常见的线程池实现(如FixedThreadPool、CachedThreadPool、ScheduledThreadPool等)的特点及使用场景。接着,通过一个电商系统订单处理的实际案例,分析了线程池参数设置不当导致的性能问题,并提出了相应的优化策略。最终,总结了线程池优化的最佳实践,旨在帮助开发者更好地利用Java线程池提升应用性能和稳定性。 ####
|
17天前
|
Java 程序员
Java社招面试题:& 和 && 的区别,HR的套路险些让我翻车!
小米,29岁程序员,分享了一次面试经历,详细解析了Java中&和&&的区别及应用场景,展示了扎实的基础知识和良好的应变能力,最终成功获得Offer。
45 14
|
17天前
|
缓存 Java 开发者
Java多线程编程的陷阱与最佳实践####
本文深入探讨了Java多线程编程中常见的陷阱,如竞态条件、死锁和内存一致性错误,并提供了实用的避免策略。通过分析典型错误案例,本文旨在帮助开发者更好地理解和掌握多线程环境下的编程技巧,从而提升并发程序的稳定性和性能。 ####
|
10天前
|
安全 算法 Java
Java多线程编程中的陷阱与最佳实践####
本文探讨了Java多线程编程中常见的陷阱,并介绍了如何通过最佳实践来避免这些问题。我们将从基础概念入手,逐步深入到具体的代码示例,帮助开发者更好地理解和应用多线程技术。无论是初学者还是有经验的开发者,都能从中获得有价值的见解和建议。 ####
|
11天前
|
Java 调度
Java中的多线程编程与并发控制
本文深入探讨了Java编程语言中多线程编程的基础知识和并发控制机制。文章首先介绍了多线程的基本概念,包括线程的定义、生命周期以及在Java中创建和管理线程的方法。接着,详细讲解了Java提供的同步机制,如synchronized关键字、wait()和notify()方法等,以及如何通过这些机制实现线程间的协调与通信。最后,本文还讨论了一些常见的并发问题,例如死锁、竞态条件等,并提供了相应的解决策略。
30 3
|
12天前
|
监控 Java 开发者
深入理解Java中的线程池实现原理及其性能优化####
本文旨在揭示Java中线程池的核心工作机制,通过剖析其背后的设计思想与实现细节,为读者提供一份详尽的线程池性能优化指南。不同于传统的技术教程,本文将采用一种互动式探索的方式,带领大家从理论到实践,逐步揭开线程池高效管理线程资源的奥秘。无论你是Java并发编程的初学者,还是寻求性能调优技巧的资深开发者,都能在本文中找到有价值的内容。 ####
|
17天前
|
缓存 Java 开发者
Java多线程并发编程:同步机制与实践应用
本文深入探讨Java多线程中的同步机制,分析了多线程并发带来的数据不一致等问题,详细介绍了`synchronized`关键字、`ReentrantLock`显式锁及`ReentrantReadWriteLock`读写锁的应用,结合代码示例展示了如何有效解决竞态条件,提升程序性能与稳定性。
54 6
|
15天前
|
监控 Java 数据库连接
Java线程管理:守护线程与用户线程的区分与应用
在Java多线程编程中,线程可以分为守护线程(Daemon Thread)和用户线程(User Thread)。这两种线程在行为和用途上有着明显的区别,了解它们的差异对于编写高效、稳定的并发程序至关重要。
24 2