1.是否掌握线程、进程、协程的区别
能否解释下什么是进程、线程、协程,他们之间的关系是怎样的
协程对于多线程有什么优缺点吗
2.是否清晰表达并发+并行的区别
说下并发和并行的区别,举些例子说下
3.Java多线程的实现方式和区别
你知道java里面实现多线程有哪几种方式,有什么不同,比较常用哪种
继承Thread
public class test {
public static void main(String[] args) {
ThreadDemo threadDemo = new ThreadDemo();
threadDemo.setName("demo1");
threadDemo.start();
System.out.println("主线程:"+Thread.currentThread().getName());
}
}
public class ThreadDemo extends Thread{
@Override
public void run() {
System.out.println("继承Thread实现多线程,名称:"+Thread.currentThread().getName());
}
}
主线程:main
继承Thread实现多线程,名称:demo1
实现Runnable
public class test {
public static void main(String[] args) {
ThreadDemo2 threadDemo2 = new ThreadDemo2();
Thread thread = new Thread(threadDemo2);
thread.setName("demo2");
thread.start();
System.out.println("主线程名称:"+Thread.currentThread().getName());
}
}
public class ThreadDemo extends Thread{
@Override
public void run() {
System.out.println("继承Thread实现多线程,名称:"+Thread.currentThread().getName());
}
}
JDK8之后采用lambda表达式
public class test {
public static void main(String[] args) {
Thread thread = new Thread(()->{
System.out.println("通过Runnable实现多线程,名称:"+Thread.currentThread().getName());
});
thread.setName("demo2");
thread.start();
System.out.println("主线程名称:"+Thread.currentThread().getName());
}
} 主线程名称:main
通过Runnable实现多线程,名称:demo2
通过Callable和FutureTask方式
import java.util.concurrent.Callable;
public class MyTask implements Callable<Object> {
@Override
public Object call() throws Exception {
System.out.println("通过Callable实现多线程,名称:"+Thread.currentThread().getName());
return "这是返回值";
}
}
public class test {
public static void main(String[] args) {
FutureTask<Object> futureTask = new FutureTask<>(()->{
System.out.println("通过Callable实现多线程,名称:"+Thread.currentThread().getName());
return "这是返回值";
});
// MyTask myTask = new MyTask();
// FutureTask<Object> futureTask = new FutureTask<>(myTask);
//FutureTask继承了Runnable,可以放在Thread中启动执行
Thread thread = new Thread(futureTask);
thread.setName("demo3");
thread.start();
System.out.println("主线程名称:"+Thread.currentThread().getName());
try {
System.out.println(futureTask.get());
} catch (InterruptedException e) {
//阻塞等待中被中断,则抛出
e.printStackTrace();
} catch (ExecutionException e) {
//执行过程发送异常被抛出
e.printStackTrace();
}
}
} 主线程名称:main
通过Callable实现多线程,名称:demo3
这是返回值
通过线程池创建线程
public class ThreadDemo4 implements Runnable {
@Override
public void run() {
System.out.println("通过线程池+runnable实现多线程,名称:"+Thread.currentThread().getName());
}
}
public class test {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(3);
for(int i=0;i<10;i++){
executorService.execute(new ThreadDemo4());
}
System.out.println("主线程名称:"+Thread.currentThread().getName());
//关闭线程池
executorService.shutdown();
}
} 主线程名称:main
通过线程池+runnable实现多线程,名称:pool-1-thread-3
通过线程池+runnable实现多线程,名称:pool-1-thread-2
通过线程池+runnable实现多线程,名称:pool-1-thread-1
通过线程池+runnable实现多线程,名称:pool-1-thread-3
通过线程池+runnable实现多线程,名称:pool-1-thread-2
通过线程池+runnable实现多线程,名称:pool-1-thread-3
通过线程池+runnable实现多线程,名称:pool-1-thread-1
通过线程池+runnable实现多线程,名称:pool-1-thread-3
通过线程池+runnable实现多线程,名称:pool-1-thread-2
通过线程池+runnable实现多线程,名称:pool-1-thread-1
4.线程有几种状态有哪些,分别解释下
java线程常见的基本状态有哪些,这些状态分别是做什么的
5.常见线程的api操作是否熟悉
是否了解多线程开发里面常用的方法,sleep/yield/join wait/notify/notifyAll, 分别解释下
6.线程有几种状态和API,画出转换流程图
看来挺熟悉多线程的,那你画下线程的状态转换图和这些转换过程常用的api也标记下
7.并发编程常见知识点考查
平时业务代码里面使用过多线程吗,能举例几个多线程的业务场景吗?
能举几个不是线程安全的数据结构吗?
在Java中可以有哪些方法来保证线程安全
了解volatile关键字不?能否解释下,然后这和synchronized有什么大的区别
补充知识——原子性
即一个操作或者多个操作,要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行。原子性就像数据库里面的事务一样,他们是一个团队,同生共死。
一个很经典的例子就是银行账户转账问题:比如从账户A向账户B转1000元,那么必然包括2个操作:从账户A减去1000元,往账户B加上1000元。试想一下,如果这2个操作不具备原子性,会造成什么样的后果。假如从账户A减去1000元之后,操作突然中止。然后又从B取出了500元,取出500元之后,再执行 往账户B加上1000元 的操作。这样就会导致账户A虽然减去了1000元,但是账户B没有收到这个转过来的1000元。
所以这2个操作必须要具备原子性才能保证不出现一些意外的问题。同样地反映到并发编程中会出现什么结果呢?举一个简单的例子:
i = 0; //1 j = i ; //2 i++; //3 i = j + 1; //4
上面四个操作,有哪个几个是原子操作,那几个不是?如果不是很理解,可能会认为都是原子性操作,其实只有1才是原子操作,其余均不是。
在单线程环境下我们可以认为整个步骤都是原子性操作,但是在多线程环境下则不同,Java只保证了基本数据类型的变量和赋值操作才是原子性的(注:在32位的JDK环境下,对64位数据的读取不是原子性操作*,如long、double)。
要想在多线程环境下保证原子性,则可以通过锁、synchronized来确保。volatile是无法保证复合操作的原子性。
为什么会出现脏读?
你说volatile可以避免指令重排,能否解释下什么是指令重排
知道 happens-before吗,能否简单解释下?
本文作者为DBC,转载请注明。

