java线程相关题目

进程是系统中拥有资源的一个基本单位。(相当于一个程序)

线程是系统中调度和分派的基本单位。它被包括在进程中。(能够执行代码的执行单元)

&多线程的好处:1.发挥多核cpu的优势 2.防止阻塞. 3.方便建模(大任务分解成小任务,通过多线程分别运行,简单多了)

&创建线程的三种方式:

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

2.实现runnable接口,并实现该接口的run()方法。(推荐使用)

3.实现Callable接口,重写call()方法。(Executor框架的功能类,可以提供返回值,可以抛出异常)

&同步和异步的区别:同步就是等待返回结构,只有结果返回了才往下继续执行。(一般在多线程环境中,需要访问同一个资源时,为了确保该资源在同一时刻只能一个线程访问,否则运行的结构无法预料,这个时候使用同步)。异步就是不需要等待返回结果,可以直接运行接下来的程序。(节省了时间,提高程序的效率)

&run()方法和start()方法的区别:系统通过调用start()方法来启动一个线程,此时线程处于就绪状态而非运行状态,也就意味着JVM可以调度这个线程。在调度过程中,通过线程类的run()方法来完成实际的操作,当run()方法结束后,线程就终结了。

如果直接调用run()方法,这会被当做一个普通的函数调用,程序中仍然只有主线程这一个线程。

也就是说,start()方法能够异步的调用run()方法,但是直接调用run()方法却是同步的,因此无法达到多线程的目的。

&sleep()方法与wait()方法的区别:1).都是使线程暂停的方法。但是sleep()方法是Thread类的静态方法,它会把执行机会让给其它线程。而wait()方法是Object类的方法,这个方法会使当前拥有该对象锁的进程等待,直到其它线程调用notify()方法才醒过来。2).sleep()方法是让线程暂停执行一段时间,时间一到自动恢复,不涉及线程间的通信。因此,调用sleep()方法不会释放锁。而wait()方法会释放掉它所占用的锁,从而使线程所在对象的其它synchronized数据可以被别的线程使用。3).由于wait()方法的特殊意义,因此它必须放在同步控制方法或同步语句块中。但是sleep()方法可以放在任意地方使用。4).sleep()方法必须捕获异常。在sleep的过程中,有可能被其他对象调用它的interrupt(),产生InterruptedException异常。

&join()方法:让调用该方法的线程在执行完run()方法后,再执行调用的线程join方法后面的代码。具体而言,可以通过线程A的join方法来等待线程A的结束,使先执行线程A的代码。也可以设置等待时间。

现有T1、T2、T3三个线程,使它们依次执行,T2在T1执行完之后执行,T3在T2执行之后执行:

public static void main(String[] args) {
        method01();
        method02();
    }

    /**
     * 第一种实现方式,顺序写死在线程代码的内部了,有时候不方便
     */
    private static void method01() {
        Thread t1 = new Thread(new Runnable() {
            @Override public void run() {
                System.out.println("t1 is finished");
            }
        });
        Thread t2 = new Thread(new Runnable() {
            @Override public void run() {
                try {
                    t1.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("t2 is finished");
            }
        });
        Thread t3 = new Thread(new Runnable() {
            @Override public void run() {
                try {
                    t2.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("t3 is finished");
            }
        });

        t3.start();
        t2.start();
        t1.start();
    }

&多线程同步的实现方法(三种同步机制):

在多线程环境中,可能会有两个甚至更多的线程试图同时访问一个有限的资源。必须对这种潜在资源冲突进行预防。

解决方法:在线程使用一个资源时为其加锁即可。访问资源的第一个线程为其加上锁以后,其它线程便不能在使用那个资源,除非被解决。

一、

Synchronized:

当Synchronized关键字修饰一个方法的时候,该方法叫做同步方法:java中的每个对象都有一个锁(lock)或者叫做监视器(monitor),当访问某个对象的synchronized方法的时候,表示将对象上锁,此时其它任何线程都无法再去访问synchronized方法了,直到之前的那个线程执行方法完毕后(或者是抛出了异常),那么将该对象的锁释放掉,其他线程才有可能再去访问该synchronized方法。

注意1:

如果一个对象有多个synchronized方法,某一个时刻某个线程已经进入到了某个synchronized方法,那么在该方法没有执行完毕前,其它线程是无法访问该对象的任何synchronzed方法的。

注意2:

如果某个Synchronized方法是static的,那么当线程访问该方法时,它锁的并不是Synchronized方法所在的对象,而是Synchronized方法所在的对象所对象的Class对象,因为java中无论一个类有多少个对象,这些对象会对应唯一一个class对象,因此当线程分别访问同一个类的两个对象的两个static Synchronized方法的时候,他们执行的顺序也是顺序的,也就是说一个线程先去执行方法,执行完毕后另一个线程才开始执行。

Java多线程中的10个面试要点

二、

wait()方法和notify()方法:

当使用synchronized来修饰某个共享资源时,如果线程A1在执行synchronized代码,另外一个线程A2也要同时执行同一个对象的同一synchronized代码时,线程A2将要等待线程A1执行完成后,才能继续执行。在这种情况下可以使用wait()方法和notify()方法。

在synchronized代码被执行期间,线程可以调用对象的wait()方法,释放对象锁,进入等待状态,并且可以调用notify()方法或notifyAll()方法通知正在等待的其它线程。notify()方法仅唤醒一个线程(等待队列中的第一个线程)并允许它去获得锁,notifyAll()方法唤醒所有等待这个对象的线程并允许它们去获得锁(并不是让所有唤醒线程都获得锁,而是让它们去竞争)。

三、

使用重入锁Lock

ReentrantLock类是可重入、互斥、实现了Lock接口的锁, 
    它与使用synchronized方法和快具有相同的基本行为和语义,并且扩展了其能力
    ReenreantLock类的常见使用:
        ReentrantLock() : 创建一个ReentrantLock实例 
        lock() : 获得锁 
        unlock() : 释放锁 
    注:ReentrantLock()还有一个可以创建公平锁的构造方法,但由于能大幅度降低程序运行效率,不推荐使用

(四)、

还有一些其他的方法可以同步线程

volatile关键字修饰变量。

使用线程本地变量 ThreadLocal

使用阻塞队列实现线程同步(java.util.concurrent包中提供的类)

注意:Lock和synchronized的锁的机制不同,所以它们的锁相当于两种不同的锁,使用时互不影响。

&什么是守护线程:

线程分为用户线程和守护线程。守护线程的一个典型例子就是垃圾回收器。它是指在程序运行时在后台提供一种通用服务的线程。如果用户线程已经全部退出运行,只剩下守护线程存在了,JVM也就退出了。

&终止线程的3中方式
1.线程正常执行完毕,正常退出。

2.使用while()循环在特定条件下退出。

    通过设置标志来控制run()方法中的循环是否执行,从而离开run()方法终止线程。

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

3.使用interrupt方法终止线程。(会抛出异常,需捕获,让线程安全退出)

&一个线程如果出现了运行时异常会怎么样

如果这个异常没有被捕获的话,这个线程就停止执行了。另外重要的一点是: 如果这个线程持有某个某个对象的监视器,那么这个对象监视器会被立即释放

&怎么检测一个线程是否持有对象监视器

我也是在网上看到一道多线程面试题才知道有方法可以判断某个线程是否持有对象监视器:Thread类提供了一个holdsLock(Object obj)方法,当且仅当对象obj的监视器被某条线程持有的时候才会返回true,注意这是一个static方法,这意味着 "某条线程"指的是当前线程 。

&死锁:

线程A和线程B相互等待对方持有的锁导致程序无限死循环下去。

写一个死锁的程序:

(1)两个线程里面分别持有两个Object对象:lock1和lock2。这两个lock作为同步代码块的锁;

(2)线程1的run()方法中同步代码块先获取lock1的对象锁,Thread.sleep(xxx),时间不需要太多,50毫秒差不多了,然后接着获取lock2的对象锁。这么做主要是为了防止线程1启动一下子就连续获得了lock1和lock2两个对象的对象锁

(3)线程2的run)(方法中同步代码块先获取lock2的对象锁,接着获取lock1的对象锁,当然这时lock1的对象锁已经被线程1锁持有,线程2肯定是要等待线程1释放lock1的对象锁的

这样,线程1"睡觉"睡完,线程2已经获取了lock2的对象锁了,线程1此时尝试获取lock2的对象锁,便被阻塞,此时一个死锁就形成了。

&同步方法和同步块,哪个是更好的选择

同步块,这意味着同步块之外的代码是异步执行的,这比同步整个方法更提升代码的效率。请知道一条原则:同步的范围越少越好。

借着这一条,我额外提一点,虽说同步的范围越少越好,但是在Java虚拟机中还是存在着一种叫做 锁粗化 的优化方法,这种方法就是把同步范围变大。这是有用的,比方说StringBuffer,它是一个线程安全的类,自然最常用的append()方法是一个同步方法,我们写代码的时候会反复append字符串,这意味着要进行反复的加锁->解锁,这对性能不利,因为这意味着Java虚拟机在这条线程上要反复地在内核态和用户态之间进行切换,因此Java虚拟机会将多次append方法调用的代码进行一个锁粗化的操作,将多次的append的操作扩展到append方法的头尾,变成一个大的同步块,这样就减少了加锁-->解锁的次数,有效地提升了代码执行的效率。


<think>好的,我现在要处理用户关于Java线程编程面试及答案的查询。首先,我需要回顾用户提供的系统级指令,确保回答符合格式要求。用户要求所有行内数学表达式用$...$,独立公式用$$...$$,但这个问主要涉及Java线程,可能数学公式较少,不过需要注意如果有的话要正确使用。然后要使用中文回答,结构清晰,分步解决问,并生成相关。同时需要引用提供的三个参考内容,末尾添加引用标识。 首先,用户明确提到想查找关于Java线程相关的面试题目,特别是面试及答案。根据提供的引用,引用[1]提到了Java线程面试相关内容,引用[2]关于查看线程名的方法,引用[3]涉及并发、并行、串行以及多线程的优劣。我需要整合这些信息,生成相关的面试和答案。 接下来,我需要确定常见的Java线程面试,并结合提供的引用内容。例如,可能会问到并发与并行的区别(引用[3]),如何获取当前线程名(引用[2]),以及多线程的优缺点(引用[3])。此外,可能还需要包括线程生命周期、同步机制、线程池、死锁等内容,这些都是常见的面试问。 然后,我需要确保每个问都有对应的答案,并且答案中正确引用相关段落。例如,在解释并发和并行时,必须引用引用[3]的内容。在讨论线程名获取时,引用引用[2]。同时,引用[1]作为整体准备面试的参考。 同时,要检查是否符合格式要求,比如代码块使用正确的语法,行内变量如Thread.currentThread().getName()需要用$...$吗?根据示例中的Python代码,用户可能希望代码块用反引号包裹,而变量或方法名在行内可能需要用$...$,但可能这里不需要,因为示例中的Python代码并没有使用数学表达式。可能用户主要关注的是代码块的正确展示,所以需要确保代码部分用正确的格式,如Java代码块。 另外,用户要求生成相关,放在最后。需要确保相关与内容相关,并且能够帮助用户进一步学习。 现在,我需要组织这些内容,确保结构清晰,分点回答,每个问有答案,并在答案末尾添加引用。例如: 1. 并发与并行的区别? 答案:并发指多个任务在同一个CPU上交替执行... [^3] 2. 如何获取当前线程名? 答案:调用Thread.currentThread().getName() [^2] 等等。同时,在生成答案时,可能需要补充更多细节,比如线程的生命周期状态,synchronized关键字,volatile关键字,线程池的参数,死锁的产生条件等,这些都是常见的面试。 需要确保每个答案中的引用正确,例如在解释并发时引用[3],在获取线程名时引用[2],整体准备面试引用[1]。 最后,生成的相关需要围绕Java线程,比如优化多线程性能的方法,如何避免死锁,线程池的工作原理等。 检查是否有遗漏的要点,比如是否有重要的面试没有涵盖,或者引用是否正确。同时,确保LaTeX语法正确,尽管这个问可能较少涉及数学公式,但如果有变量或代码内的符号,可能需要用$包裹,比如方法名可能不需要,但如果有数学相关内容则需要。 总结步骤: 1. 列出常见Java线程面试。 2. 结合提供的引用内容,将相关与引用对应。 3. 编写每个问的答案,包含必要的代码示例和引用标记。 4. 生成相关部分。 5. 检查格式是否符合要求,如代码块、引用标识、结构清晰等。</think>### Java线程编程面试及答案 #### 1. 并发与并行的区别是什么? **答案**: - **并发**:多个任务在同一个CPU上按时间片轮流交替执行,看似同时进行,但实际是快速切换。 - **并行**:多个任务在单位时间内由多核处理器或不同处理器同时处理,是真正的同时执行[^3]。 - **示例**:单核CPU通过时间片实现并发;多核CPU可同时运行多个线程,实现并行。 #### 2. 如何获取当前线程的名称? **答案**: 调用`Thread.currentThread().getName()`即可获取当前线程的名称[^2]。 ```java public class ThreadNameExample { public static void main(String[] args) { System.out.println("当前线程名:" + Thread.currentThread().getName()); } } ``` #### 3. 多线程的优势和劣势是什么? **答案**: - **优势**: - 提高资源利用率(如多核CPU)和程序响应速度。 - 适用于高并发场景(如服务器处理请求)。 - **劣势**: - 线程安全问(如数据竞争)。 - 调试和复杂度较高。 #### 4. 线程的生命周期包含哪些状态? **答案**: 线程生命周期包括以下状态: 1. **新建(New)**:通过`new Thread()`创建,尚未启动。 2. **就绪(Runnable)**:调用`start()`后等待CPU调度。 3. **运行(Running)**:获得CPU时间片执行任务。 4. **阻塞(Blocked)**:等待锁或I/O操作。 5. **终止(Terminated)**:执行完毕或异常退出。 #### 5. 什么是线程安全?如何实现线程安全? **答案**: - **线程安全**:多线程环境下,共享资源的操作结果始终符合预期。 - **实现方法**: - 使用`synchronized`关键字对代码块或方法加锁。 - 使用`volatile`关键字保证变量可见性。 - 使用`java.util.concurrent`包中的原子类(如`AtomicInteger`)。 ```java public class Counter { private int count = 0; public synchronized void increment() { count++; } } ``` #### 6. 什么是死锁?如何避免死锁? **答案**: - **死锁**:多个线程互相持有对方需要的资源,导致无限等待。 - **避免方法**: - 按固定顺序获取锁。 - 使用超时机制(如`tryLock`)。 - 避免嵌套锁。 #### 7. 线程池有哪些核心参数? **答案**: 线程池通过`ThreadPoolExecutor`配置,核心参数包括: 1. **核心线程数(corePoolSize)**:常驻线程数量。 2. **最大线程数(maximumPoolSize)**:允许创建的最大线程数。 3. **任务队列(workQueue)**:存放待执行任务的阻塞队列。 4. **存活时间(keepAliveTime)**:非核心线程空闲时的存活时间。 #### 8. 为什么使用`volatile`关键字? **答案**: - **作用**: - 保证变量的可见性:修改后立即同步到主内存。 - 禁止指令重排序(通过内存屏障)。 - **局限性**:不保证原子性(如`count++`仍需同步)。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值