本人详解
作者:王文峰,参加过 CSDN 2020年度博客之星,《Java王大师王天师》
公众号:JAVA开发王大师,专注于天道酬勤的 Java 开发问题
中国国学、传统文化和代码爱好者的程序人生,期待你的关注和支持!本人外号:神秘小峯 山峯
转载说明:务必注明来源(注明:作者:王文峰哦)
Java多线程面试题【线程状态】【线程同步和线程通信】【多接口实现多线程】【volatile关键字】【ReentrantLock关键字】
学习教程(传送门)
1、掌握 JAVA入门到进阶知识(持续写作中……)
2、学会Oracle数据库用法(创作中……)
3、手把手教你vbs脚本制作(完善中……)
4、牛逼哄哄的 IDEA编程利器(编写中……)
5、吐血整理的 面试技巧(更新中……)
Java多线程面试题及示例
1. 请解释Java中的线程与进程的区别。
在Java中,线程是进程内的一个执行单元,它共享进程的资源(如内存空间、文件句柄等),而进程是操作系统分配资源的基本单位。线程相较于进程更加轻量级,因此线程的创建、切换和销毁的开销通常比进程小得多。
2. 请简述Java中实现多线程的几种方式。
Java中实现多线程主要有三种方式:
- 继承Thread类:通过创建一个新类继承Thread类并重写其run()方法来实现多线程。
- 实现Runnable接口:通过创建一个新类实现Runnable接口并重写其run()方法,然后将该类的对象作为参数传递给Thread类的构造方法来创建线程。
- 实现Callable和Future接口:使用Callable接口可以返回一个值或抛出异常,而Future接口用于获取Callable执行的结果。这种方式通常与ExecutorService结合使用。
3. 请解释Java中的线程状态以及它们之间的转换。
Java中的线程状态包括:
- 新建(NEW):新创建了一个线程对象。
- 就绪(RUNNABLE):线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权。
- 运行(RUNNING):线程获取了CPU使用权,执行程序代码。
- 阻塞(BLOCKED):阻塞状态是指线程因为某种原因放弃了CPU使用权,也即让出了CPU timeslice,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。
- 等待(WAITING):线程在等待另一个线程执行一个(唤醒)动作。
- 超时等待(TIMED_WAITING):和WAITING状态类似,不过它可以在指定的时间后自行返回的线程状态。
- 终止(TERMINATED):线程已退出。
4. 请说明Java中的线程同步和线程通信。
线程同步:多个线程并发访问共享数据时,为保证数据的一致性和完整性,需要对共享数据进行同步控制。Java中常用的线程同步机制包括synchronized关键字和Lock接口。
线程通信:线程通信是指线程之间以某种方式来交换信息。在Java中,线程通信的主要方式是使用wait()和notify()/notifyAll()方法,这些方法只能在同步方法或同步代码块中使用。另外,还可以使用Condition接口来实现更灵活的线程通信。
示例
使用Runnable接口实现多线程
public class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("线程 " + Thread.currentThread().getName() + " 正在运行");
}
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread thread1 = new Thread(myRunnable, "线程1");
Thread thread2 = new Thread(myRunnable, "线程2");
thread1.start();
thread2.start();
}
}
使用synchronized实现线程同步
public class SynchronizedExample {
private Object lock = new Object();
private int count = 0;
public synchronized void increment() {
count++;
}
public synchronized void decrement() {
count--;
}
public synchronized int getCount() {
return count;
}
// 示例用法
public static void main(String[] args) {
SynchronizedExample example = new SynchronizedExample();
// 创建两个线程分别进行增加和减少操作
Thread incrementThread = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
example.increment();
}
});
Thread decrementThread = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
example.decrement();
}
});
incrementThread.start();
decrementThread.start();
// 等待两个线程执行完毕
try {
incrementThread.join();
decrementThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("最终计数:" + example.getCount()); // 可能是0,也可能是其他值,取决于两个线程的执行顺序和速度
}
}
5. 请解释volatile
关键字在Java中的作用,并举例说明。
volatile
关键字是Java提供的一种轻量级的同步机制,它主要用于确保变量在多线程之间的可见性。当一个变量被声明为volatile
时,它会保证修改的值会立即被更新到主内存,当有其他线程需要读取时,它会去主内存中读取新值。但是需要注意的是,volatile
并不能保证复合操作的原子性。
示例:
public class VolatileExample {
private volatile boolean flag = false;
public void setFlag(boolean flag) {
this.flag = flag;
}
public boolean isFlag() {
return flag;
}
public static void main(String[] args) {
final VolatileExample example = new VolatileExample();
new Thread(() -> {
System.out.println("线程1开始等待flag...");
while (!example.isFlag()) {
// 等待flag变为true
}
System.out.println("线程1结束等待,flag为true");
}).start();
try {
// 让主线程暂停一段时间,模拟其他线程先运行的情况
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 在主线程中修改flag的值
example.setFlag(true);
}
}
在这个例子中,如果flag
没有被声明为volatile
,那么线程1可能永远都看不到flag
变为true
,因为它一直在读取自己线程的工作内存中的值。但是,由于flag
被声明为volatile
,线程1能够立即看到主内存中flag
的变化。
6. 请解释Java中的wait()
和notify()
/notifyAll()
方法,并给出使用它们的示例。
wait()
和notify()
/notifyAll()
是Java中用于线程间通信的方法,它们必须在同步代码块或同步方法中使用,否则会抛出IllegalMonitorStateException
。
wait()
:使当前线程等待,直到其他线程调用此对象的notify()
方法或notifyAll()
方法。当前线程必须拥有此对象的监视器(即,它必须是当前正在执行同步代码块的线程)。notify()
:唤醒在此对象监视器上等待的单个线程。notifyAll()
:唤醒在此对象监视器上等待的所有线程。
示例:
public class WaitNotifyExample {
private int count = 0;
public synchronized void increment() {
while (count == 5) {
try {
wait(); // 等待,直到其他线程调用notify()或notifyAll()
} catch (InterruptedException e) {
e.printStackTrace();
}
}
count++;
System.out.println("Count: " + count);
notifyAll(); // 唤醒所有等待的线程
}
public static void main(String[] args) {
WaitNotifyExample example = new WaitNotifyExample();
// 创建两个线程进行增加操作
new Thread(() -> {
for (int i = 0; i < 10; i++) {
example.increment();
try {
Thread.sleep(100); // 模拟耗时操作
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
example.increment();
try {
Thread.sleep(150); // 模拟耗时操作,使两个线程交替执行
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
在这个例子中,当count
达到5时,调用wait()
的线程会等待,直到其他线程调用notifyAll()
唤醒它。这样可以实现线程间的简单协作。但是,需要注意的是,wait()
和notify()
/notifyAll()
的使用需要谨慎,因为它们可能会导致死锁或活锁等问题。
7. 请解释Java中的Lock
接口和ReentrantLock
类,并比较它们与synchronized
的区别。
Lock
接口是Java并发包java.util.concurrent.locks
中的一个重要接口,它提供了比synchronized
更灵活的锁控制。ReentrantLock
是Lock
接口的一个实现类,它支持可重
学习教程(传送门)
1、掌握 JAVA入门到进阶知识(持续写作中……)
2、学会Oracle数据库用法(创作中……)
3、手把手教你vbs脚本制作(完善中……)
4、牛逼哄哄的 IDEA编程利器(编写中……)
5、吐血整理的 面试技巧(更新中……)
往期文章
第一章:日常_JAVA_面试题集15(含答案)
第二章:日常_JAVA_面试题集14(含答案)
平安壹钱包面试官:请你说一下Mybatis的实现原理
Java开发-热点-热门问题精华核心总结-推荐
往期文章大全……
一键三连 一键三连 一键三连~
本人详解
作者:王文峰,参加过 CSDN 2020年度博客之星,《Java王大师王天师》
公众号:JAVA开发王大师,专注于天道酬勤的 Java 开发问题
中国国学、传统文化和代码爱好者的程序人生,期待你的关注和支持!本人外号:神秘小峯 山峯
转载说明:务必注明来源(注明:作者:王文峰哦)
一键三连 一键三连 一键三连~
以上就是今天的内容,关注我,不迷路