1、现在有 T1、T2、T3 三个线程,你怎样保证 T2 在 T1 执行完后执行,T3 在 T2 执行完后执行?
考察 Thread.join,还有其他concurrent包下工具类的了解。
方法一:可以使用 join 方法实现等待;
方法二:可以使用 CompletableFuture 的 thenCombine 方法
public class TestOrder {
public static void main(String[] args) {
Thread thread1 = new Thread() {
@Override
public void run() {
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("thread 1");
}
};
thread1.start();
try {
thread1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
Thread thread2 = new Thread() {
@Override
public void run() {
try {
sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("thread 2");
}
};
thread2.start();
try {
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
Thread thread3 = new Thread() {
@Override
public void run() {
try {
sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("thread 3");
}
};
thread3.start();
}
}
2、在 java 中 wait 和 sleep 方法的不同?
sleep 是 Thread 类的方法;wait是 Object 的方法。
此外,wait 期间会释放锁,sleep期间会持有锁。wait通常用于线程交互,sleep一般用于暂停执行。
3、什么是竞争条件?你怎样发现和解决竞争?
在并发编程中,由于不恰当的执行时序而出现不正确的结果是一种非常重要的情况,它的正式名字就叫竞态条件。
或者可以说:当某个计算的正确性取决于多个线程的交替执行时序时,那么就会发生竞态条件。
换句话说,就是正确的结果取决于运气。
发生场景:最常见的场景就是 “先检查再执行”
例子:
public ExpensiveObject getInstance() {
// 先检查后执行,这种场景下会发生竞态条件
if (instance == null) {
instance = new ExpensiveObject();
}
return instance;
}
4、Java 中你怎样停止或者取消一个线程?
如果不是因为IO阻塞,常见的
https://blog.youkuaiyun.com/Prepared/article/details/114164117
5、什么是不可变对象,它对写并发应用有什么帮助?
满足以下条件时,对象才是不可变的:
1、对象创建以后其状态就不能修改;
2、对象的所有域都是final类型;
3、对象是正确创建的(在对象的创建期间,this引用没有逸出)
说明:即使对象中的所有的域都是final类型的,这个对象也仍然是可变的。
6、用 Java 编程一个会导致死锁的程序,你将怎么解决?
两个线程,线程A持有资源C,等待持有资源D;线程B持有资源D,等待持有资源C。
一个常见的场景是转账:银行A,持有转入账户,等待持有转出账户;银行B,持有转出账户,等待持有转入账户。
以下是一个例子,互相持有对方持有的锁
public class Test1001LeftRightDeadLock {
private final Object left = new Object();
private final Object right = new Object();
public void leftRight() {
synchronized (left) {
doSomething();
}
}
private void doSomething() {
}
private void doSomethingElse() {
}
public void rightLeft() {
synchronized (right) {
doSomethingElse();
}
}
}
7、什么是原子操作,Java 中的原子操作是什么?
假定有两个操作A和B,如果从执行A的线程来看,当另一个线程执行B时,要么将B全部执行完,要不完全不执行B,那么A和B对彼此来说就是原子的。原子操作是指,对于访问同一个状态的所有操作(包括该操作本身)来说,这个操作是一个以原子方式执行的操作,
举例:count++
不是原子操作,先要获取count的值,然后执行+1的操作。
其中获取值是原子操作。
8、Java 中的 volatile 关键是什么作用?怎样使用它?在 Java 中它跟 synchronized 方法有什么不同?
volatile 有两个作用,一个是禁止指令重排序,另一是保证可见性。
synchronized 除了这两个作用之外,还可以锁住资源,限制资源同时只能有一个线程访问。
9、为什么我们调用 start()方法时会执行 run()方法,为什么我们不能直接调用 run()方法?
当你调用 start()方法时你将创建新的线程,并且执行在 run()方法里的代码。
但是如果你直接调用 run()方法,它不会创建新的线程也不会执行调用线程的代码。
10、用 Java 实现阻塞队列
入队操作,如果队列已满,需要等待队列不满,使用await方法;入队之后,通知出队线程;
出队操作,如果队列为空,需要等待队列不空,使用await方法;出队之后,通知入队线程;
public class BlockedQueue<T> {
final Lock lock = new ReentrantLock();
// 条件变量:队列不满
final Condition notFull = lock.newCondition();
// 条件变量:队列不空
final Condition notEmpty = lock.newCondition();
// 入队
void enq(T x) {
lock.lock();
try {
// 队列已满
boolean flag = true;
while (flag) {
// 等待队列不满
notFull.await();
}
// 省略入队操作...
//入队后,通知可出队
notEmpty.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
// 出队
void deq() {
lock.lock();
try {
// 队列已空
boolean flag = true;
while (flag) {
// 等待队列不空
notEmpty.await();
}
// 省略出队操作...
//出队后,通知可入队
notFull.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}