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()

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

待整理

相关文章
|
3天前
|
安全 Java 测试技术
Java并行流陷阱:为什么指定线程池可能是个坏主意
本文探讨了Java并行流的使用陷阱,尤其是指定线程池的问题。文章分析了并行流的设计思想,指出了指定线程池的弊端,并提供了使用CompletableFuture等替代方案。同时,介绍了Parallel Collector库在处理阻塞任务时的优势和特点。
|
3天前
|
存储 算法 Java
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
本文详解自旋锁的概念、优缺点、使用场景及Java实现。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
|
3天前
|
存储 安全 Java
Java多线程编程的艺术:从基础到实践####
本文深入探讨了Java多线程编程的核心概念、应用场景及其实现方式,旨在帮助开发者理解并掌握多线程编程的基本技能。文章首先概述了多线程的重要性和常见挑战,随后详细介绍了Java中创建和管理线程的两种主要方式:继承Thread类与实现Runnable接口。通过实例代码,本文展示了如何正确启动、运行及同步线程,以及如何处理线程间的通信与协作问题。最后,文章总结了多线程编程的最佳实践,为读者在实际项目中应用多线程技术提供了宝贵的参考。 ####
|
3天前
|
Java
JAVA多线程通信:为何wait()与notify()如此重要?
在Java多线程编程中,`wait()` 和 `notify()/notifyAll()` 方法是实现线程间通信的核心机制。它们通过基于锁的方式,使线程在条件不满足时进入休眠状态,并在条件满足时被唤醒,从而确保数据一致性和同步。相比其他通信方式,如忙等待,这些方法更高效灵活。 示例代码展示了如何在生产者-消费者模型中使用这些方法实现线程间的协调和同步。
11 3
|
1天前
|
安全 Java
Java多线程集合类
本文介绍了Java中线程安全的问题及解决方案。通过示例代码展示了使用`CopyOnWriteArrayList`、`CopyOnWriteArraySet`和`ConcurrentHashMap`来解决多线程环境下集合操作的线程安全问题。这些类通过不同的机制确保了线程安全,提高了并发性能。
|
5天前
|
存储 缓存 Java
大厂面试必看!Java基本数据类型和包装类的那些坑
本文介绍了Java中的基本数据类型和包装类,包括整数类型、浮点数类型、字符类型和布尔类型。详细讲解了每种类型的特性和应用场景,并探讨了包装类的引入原因、装箱与拆箱机制以及缓存机制。最后总结了面试中常见的相关考点,帮助读者更好地理解和应对面试中的问题。
22 4
|
2天前
|
Java
java小知识—进程和线程
进程 进程是程序的一次执行过程,是系统运行的基本单位,因此进程是动态的。系统运行一个程序即是一个进程从创建,运行到消亡的过程。简单来说,一个进程就是一个执行中的程序,它在计算机中一个指令接着一个指令地执行着,同时,每个进程还占有某些系统资源如CPU时间,内存空间,文件,文件,输入输出设备的使用权等等。换句话说,当程序在执行时,将会被操作系统载入内存中。 线程 线程,与进程相似,但线程是一个比进程更小的执行单位。一个进程在其执行的过程中产生多个线程。与进程不同的是同类的多个线程共享同一块内存空间和一组系统资源,所以系统在产生一个线程,或是在各个线程之间做切换工作时,负担要比
10 1
|
3天前
|
Java UED
Java中的多线程编程基础与实践
【10月更文挑战第35天】在Java的世界中,多线程是提升应用性能和响应性的利器。本文将深入浅出地介绍如何在Java中创建和管理线程,以及如何利用同步机制确保数据一致性。我们将从简单的“Hello, World!”线程示例出发,逐步探索线程池的高效使用,并讨论常见的多线程问题。无论你是Java新手还是希望深化理解,这篇文章都将为你打开多线程的大门。
|
5天前
|
存储 Java 程序员
Java基础的灵魂——Object类方法详解(社招面试不踩坑)
本文介绍了Java中`Object`类的几个重要方法,包括`toString`、`equals`、`hashCode`、`finalize`、`clone`、`getClass`、`notify`和`wait`。这些方法是面试中的常考点,掌握它们有助于理解Java对象的行为和实现多线程编程。作者通过具体示例和应用场景,详细解析了每个方法的作用和重写技巧,帮助读者更好地应对面试和技术开发。
34 4
|
3天前
|
安全 Java 编译器
Java多线程编程的陷阱与最佳实践####
【10月更文挑战第29天】 本文深入探讨了Java多线程编程中的常见陷阱,如竞态条件、死锁、内存一致性错误等,并通过实例分析揭示了这些陷阱的成因。同时,文章也分享了一系列最佳实践,包括使用volatile关键字、原子类、线程安全集合以及并发框架(如java.util.concurrent包下的工具类),帮助开发者有效避免多线程编程中的问题,提升应用的稳定性和性能。 ####
21 1