1. 线程有哪几种状态以及各种状态之间的转换?(必会)
看图:
线程一共有4种状态,分别是:
1.创建/新生状态new:被new出来了,还没start()。
2.就绪状态runable:start()了,待会去抢cpu。
抢到了cpu就是传说中的第五种状态运行状态running。(说好的5种呢)
这第六种的运行状态,运行的就是run()中的代码。
3.阻塞状态:运行run运行到一半,脾气一耍,不运行了,等条件蛮足了心情好了再运行。
有三种情况:
1)等待waiting:玩wait()玩的
2)计时等待time waiting: sleep() 或 join()或发出了 I/O 请求搞的。
3)阻塞blocked:被synchronized锁了
4.死亡状态terminated:run里面代码跑完了,就死了
补充:start和run方法的区别
1.类型上,start是同步方法,run是非同步方法。
2.作用上,run方法存放任务代码,start方法启动线程线程
3.对线程数量的影响方面,run不会产生新线程,start会产生新线程
4.调用次数方面,run方法可以被执行无数次,而star方法只能被执行一次,因为线程不能被重复启动
结合2、3点作用可以回答:
再补充:简述在main方法中运行线程的start方法和run方法,有什么区别,请看题:
class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
}
}
}
public class TestThread {
public static void main(String[] args) {
Thread t0 = new MyThread();
Thread t1 = new MyThread();
Thread t2 = new MyThread();
Thread t3 = new MyThread();
t0.start();
t1.start();
System.out.println("=================================");
t2.run();
t3.run();
}
}
以上代码的运行结果是什么样的?
A.
thread-0 0 // t0启动
thread-0 1
thread-0 2
thread-1 0 // t1启动
thread-1 1
... // t0和t1交替运行,打印0到99
thread-0 99
thread-1 99
=================================
thread-2 0 // t2.run()启动
thread-2 1
thread-3 0 // t3.run()启动
thread-3 1
... // t2run和t3run交替运行,打印0到99
thread-3 99
thread-2 99
B.
=================================
thread-0 0 // t0启动
thread-0 1
thread-0 2
thread-1 0 // t1启动
thread-1 1
main 0 // t2.run()启动
main 1
... // t0、t1和t2run交替运行,打印0到99
thread-0 99
thread-1 99
main 99
main 0 // t3.run()启动
main 1
... // t3run运行,打印0到99
main 99
C.
thread-0 0 // t0启动
thread-0 1
thread-0 2
thread-1 0 // t1启动
thread-1 1
... // t0和t1交替运行,打印0到99
thread-0 99
thread-1 99
=================================
main 0 // t2.run()启动
main 1
... // t2run运行,打印0到99
main 99
main 0 // t3.run()启动
main 1
... // t3run运行,打印0到99
main 99
D.
=================================
thread-0 0 // t0启动
thread-0 1
thread-0 2
thread-1 0 // t1启动
thread-1 1
main 0 // t2.run()启动
main 1
main 0 // t3.run()启动
main 1
... // t0、t1和t2run、t3run交替运行,打印0到99
thread-1 99
main 99
main 99
thread-0 99
答案是B。原因需要结合上面的2、3点来理解。
2.作用上,run方法存放任务代码,start方法启动线程线程
3.对线程数量的影响方面,run不会产生新线程,start会产生新线程
再再补充:变种题
class MyThread extends Thread {
@Override
public void run() {
synchronized (this) { // 注意这里加了个线程锁
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
}
}
}
}
public class TestThread {
public static void main(String[] args) {
Thread t0 = new MyThread();
Thread t1 = new MyThread();
Thread t2 = new MyThread();
Thread t3 = new MyThread();
t0.start();
t1.start();
System.out.println("=================================");
t0.run(); // 注意这里改成t0了
t3.run();
}
}
这个结果又是什么样的?注释掉打印分隔的等号呢:
public class TestThread2 {
public static void main(String[] args) {
Thread t0 = new MyThread();
Thread t1 = new MyThread();
Thread t2 = new MyThread();
Thread t3 = new MyThread();
t0.start();
t1.start();
// 注意注释掉了打印等号分隔
// System.out.println("=================================");
t0.run(); // 注意这里改成t0了
t3.run();
}
}
再再再补充:变变种种题
代码如下:
public class MyRun implements Runnable {
@Override
public void run() {
synchronized (this) {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
}
}
}
}
public class TestThread {
public static void main(String[] args) {
MyRun myRun = new MyRun();
Thread thread0 = new Thread(myRun);
Thread thread1 = new Thread(myRun);
thread0.start();
thread1.start();
System.out.println("=================================");
thread0.run();
}
}
2. 什么是单例模式?有几种?
单例模式有5种:
1.饿汉式(Eager Initialization)
类加载的时候就创建。
优点:实现简单、线程安全,不会出现多线程问题;
缺点:实例没有被使用,就会造成资源浪费。
2.懒汉式(Lazy Initialization)
首次使用才创建。
优点:延迟实例化,节省了资源。
缺点:线程不安全。
3.双重检查锁(Double-Checked Locking)
懒汉式加同步锁。
优点:线程安全。
缺点:实现相对复杂,可能存在某些编译器和指令重排序的问题。
4.静态内部类(Static Inner Class)
放在静态内部类中,类加载时保证线程安全。
优点:线程安全且不依赖同步锁。
缺点:实现相对复杂,需要理解静态内部类的特性。
5.枚举(Enum)
用枚举类实现创建、保存单例实例。
优点:实现简单,线程安全,且能防止反射和序列化破坏单例。
缺点:不够灵活,不能延迟实例化。
饿汉的创建详细情况描述补充。
懒汉的创建详情描述补充。
饿汉加静态代码块、懒汉加同步方法的区别,研究这篇文章再补充:
单例模式的八种类型_单例有几种_神偷奶爸的博客-CSDN博客
3. List 和 Map、Set 的区别
集合存储本质方式不同:
List和Set是单列集合,存储一种数据;Map是双列集合,存储键值对数据。
集合内部存储规律不同:
List内数据是有序的,并且可以重复;
Set内数据是无序的,且不可以重复;
Map内数据是无序的,键不能重复,值可以重复。
关于Set中位置的进一步解析
Set中的位置是固定的,但这没有顺序,还是无序的。
Set中元素的位置由hashcode决定,而这个是固定的。但这个是用户不能控制的,所以还算是无序的。
4. 使用HashMap集合储存数据,什么情况会产生hash冲突?
计算出的hashcode,即哈希值相同时,会产生hash冲突。
5. Runnable 和 Callable 的区别?
返回上:
Runnable无返回值;Callable有返回值。
异常处理上:
Runnable只能抛出运行时异常,且无法捕获处理;Callable允许抛出异常,可以获取异常信息。