2年半第一次出去面试,也是第一次面试阿里,打击不小,收货也不少,最终倒在二面笔试题上,虽有不甘,但仍需收拾心情,继续努力。
在一面上,跟网上大多数的反馈相同,都是比较Java基础项,然后往深度问。我整理了下:
因为我简历上写了关于修改Apollo(携程的配置中心)源码,应用到我们系统中,所以问了我怎么实现,还问到了配置是推还是拉,我果断回答了拉,然后大致就结束了,其中细节不多数。
后面就开始问了关于Java基础知识点了,先是问了HashMap线程安全,后面问了其中的hash值是如何确定的,为何每次扩展只能2的倍数。回答完这个之后,问有没有线程安全的HashMap,自然过渡到ConcurrentHashMap,问是如何实现线程安全的。然后回答了分段锁,之后又问了关于JDK1.8前后的实现,为什么要改为使用synchronized,回答了synchronized是jvm层实现的,后期jvm优化,会跟随着一起优化。
关于Map的问完,开始问ThreadLocal相关知识点了,是如何实现线程变量的,然后巴拉巴拉说了代码实现,还有关于ThreadLocalMap的数据结果是跟Jdk1.8之前的HashMap相似。
最后基础问完了,因为回答的都算比较流畅,所以时间过得也比较少,这里问了我关于秒杀系统怎么设计,我就回答了使用redis和MQ来进行削峰,使用redis存储库存,使用MQ进行异步业务处理。后面追问了关于redis集群如果挂了怎么办。我当时没有想到很好的方法,只想到了多级缓存,但是感觉答案不对。然后我提问了怎么解决,方案是加机器和多级缓存,就算数据错误,也要保住服务可用。
到这大致一面就结束了。
这里发生了点事,因为我是住在拱墅这,然后面试部门是在滨江,我当时问了下能否换职场位置,然后他说不能,我也没太在意,想着自己换地方。之后等了5天,没有收到反应,然后有人提醒下我去找了Boss上的推荐人,问了下,他说一面是通过了,但是备注上写着居住太远,意愿不强吧,差点没给我二面的机会了。问了之后再跟他反应这个没事,然后就顺利约到11号二面了,因为10号阿里20周年年会。
这面说实话有点可惜了。首先我这面是笔试题,之前一直在猜测会考哪方面的,网上也找了点资料,最后还是觉得会考多线程这块。当时想着应该会有代码自动补全功能把,因为我平时打代码大多数还是依靠这个功能的,有些api方法和关键字名可能拼不全。然后首先第一个给我的打击就是全程txt文件上直接手打,不能使用代码补全。之后再来说下关于面试题目把:
有三个线程,线程一只打印t1,线程二只打印t2,线程三只打印t3,输出到三个文件,第一个文件的打印顺序是t1 t2 t3 。。。第二个是t2 t3 t1 。。。 第三个是t3 t1 t2
看到这个题目,有点虚,主要文件操作这块的api记不全,如果可以找资料倒是可以。然后面试官了解了之后给我改了下题目:
有三个线程,线程一只打印t1,线程二只打印t2,线程三只打印t3,在控制台上输出t1 t2 t3 。。循环5遍 之后输出t2 t3 t1。。5遍 再输出t3 t1 t2。。5遍之后就循环
先来看第一题:
有三个线程,线程一只打印t1,线程二只打印t2,线程三只打印t3,输出到三个文件,第一个文件的打印顺序是t1 t2 t3 。。。第二个是t2 t3 t1 。。。 第三个是t3 t1 t2
哎,这题比较简单,当时主要还是文件流的类不熟,自己手写不会拼写,下面给出之后我自己写的两个答案:
第一个是使用notify实现:
/**
* 有三个线程,线程一只打印t1,线程二只打印t2,线程三只打印t3,输出到三个文件,
* 第一个文件的打印顺序是t1 t2 t3 。。。第二个是t2 t3 t1 。。。 第三个是t3 t1 t2
*
* 使用notify实现
*/
public class DemoTest {
/**
* 次数标识,用来区分那个线程打印
*/
private static volatile int count = 0;
private static Object lock = new Object();
private static File fileA = new File("/Users/shileizhou/test/fileA.txt");
private static File fileB = new File("/Users/shileizhou/test/fileB.txt");
private static File fileC = new File("/Users/shileizhou/test/fileC.txt");
public static void main(String[] args) {
try {
fileA.createNewFile();
fileB.createNewFile();
fileC.createNewFile();
BufferedWriter bufferedWriterA = new BufferedWriter(new FileWriter(fileA,true));
BufferedWriter bufferedWriterB = new BufferedWriter(new FileWriter(fileB,true));
BufferedWriter bufferedWriterC = new BufferedWriter(new FileWriter(fileC,true));
PrintT1Thread printT1Thread = new PrintT1Thread();
printT1Thread.bufferedWriterA = bufferedWriterA;
printT1Thread.bufferedWriterB = bufferedWriterB;
printT1Thread.bufferedWriterC = bufferedWriterC;
PrintT2Thread printT2Thread = new PrintT2Thread();
printT2Thread.bufferedWriterA = bufferedWriterA;
printT2Thread.bufferedWriterB = bufferedWriterB;
printT2Thread.bufferedWriterC = bufferedWriterC;
PrintT3Thread printT3Thread = new PrintT3Thread();
printT3Thread.bufferedWriterA = bufferedWriterA;
printT3Thread.bufferedWriterB = bufferedWriterB;
printT3Thread.bufferedWriterC = bufferedWriterC;
new Thread(printT1Thread).start();
new Thread(printT2Thread).start();
new Thread(printT3Thread).start();
} catch (IOException e) {
e.printStackTrace();
}
}
static class PrintT1Thread implements Runnable {
BufferedWriter bufferedWriterA ;
BufferedWriter bufferedWriterB ;
BufferedWriter bufferedWriterC ;
@Override
public void run() {
while (true){
synchronized (lock) {
try {
if (count % 3 == 0) {
bufferedWriterA.write("t1");
bufferedWriterA.flush();
if (count != 0) {
bufferedWriterB.write("t1");
bufferedWriterC.write("t1");
bufferedWriterB.flush();
bufferedWriterC.flush();
}
count++;
lock.notifyAll();
} else {
lock.wait();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
static class PrintT2Thread implements Runnable {
BufferedWriter bufferedWriterA ;
BufferedWriter bufferedWriterB ;
BufferedWriter bufferedWriterC ;
@Override
public void run() {
while (true){
synchronized (lock) {
try {
if (count % 3 == 1) {
bufferedWriterA.write("t2");
bufferedWriterB.write("t2");
bufferedWriterA.flush();
bufferedWriterB.flush();
if (count > 1) {
bufferedWriterC.write("t2");
bufferedWriterC.flush();
}
count++;
lock.notifyAll();
} else {
lock.wait();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
static class PrintT3Thread implements Runnable {
BufferedWriter bufferedWriterA ;
BufferedWriter bufferedWriterB ;
BufferedWriter bufferedWriterC ;
@Override
public void run() {
while (true){
synchronized (lock) {
try {
if (count % 3 == 2) {
bufferedWriterA.write("t3");
bufferedWriterB.write("t3");
bufferedWriterC.write("t3");
bufferedWriterA.flush();
bufferedWriterB.flush();
bufferedWriterC.flush();
count++;
lock.notifyAll();
} else {
lock.wait();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
}
第二种是使用condition方式实现:
/**
* 有三个线程,线程一只打印t1,线程二只打印t2,线程三只打印t3,输出到三个文件,
* 第一个文件的打印顺序是t1 t2 t3 。。。第二个是t2 t3 t1 。。。 第三个是t3 t1 t2
*
* 使用Condition
*/
public class DemoTest2 {
/**
* 次数标识,用来区分那个线程打印
*/
private static volatile int count = 0;
private static Lock lock = new ReentrantLock();
private static Condition t1Condition = lock.newCondition();
private static Condition t2Condition = lock.newCondition();
private static Condition t3Condition = lock.newCondition();
private static File fileA = new File("/Users/shileizhou/test/fileA.txt");
private static File fileB = new File("/Users/shileizhou/test/fileB.txt");
private static File fileC = new File("/Users/shileizhou/test/fileC.txt");
public static void main(String[] args) {
try {
fileA.createNewFile();
fileB.createNewFile();
fileC.createNewFile();
BufferedWriter bufferedWriterA = new BufferedWriter(new FileWriter(fileA,true));
BufferedWriter bufferedWriterB = new BufferedWriter(new FileWriter(fileB,true));
BufferedWriter bufferedWriterC = new BufferedWriter(new FileWriter(fileC,true));
DemoTest.PrintT1Thread printT1Thread = new DemoTest.PrintT1Thread();
printT1Thread.bufferedWriterA = bufferedWriterA;
printT1Thread.bufferedWriterB = bufferedWriterB;
printT1Thread.bufferedWriterC = bufferedWriterC;
DemoTest.PrintT2Thread printT2Thread = new DemoTest.PrintT2Thread();
printT2Thread.bufferedWriterA = bufferedWriterA;
printT2Thread.bufferedWriterB = bufferedWriterB;
printT2Thread.bufferedWriterC = bufferedWriterC;
DemoTest.PrintT3Thread printT3Thread = new DemoTest.PrintT3Thread();
printT3Thread.bufferedWriterA = bufferedWriterA;
printT3Thread.bufferedWriterB = bufferedWriterB;
printT3Thread.bufferedWriterC = bufferedWriterC;
new Thread(printT1Thread).start();
new Thread(printT2Thread).start();
new Thread(printT3Thread).start();
} catch (IOException e) {
e.printStackTrace();
}
}
static class PrintT1Thread implements Runnable {
BufferedWriter bufferedWriterA ;
BufferedWriter bufferedWriterB ;
BufferedWriter bufferedWriterC ;
@Override
public void run() {
while (true){
lock.lock();
try {
if (count % 3 == 0) {
bufferedWriterA.write("t1");
bufferedWriterA.flush();
if (count != 0) {
bufferedWriterB.write("t1");
bufferedWriterC.write("t1");
bufferedWriterB.flush();
bufferedWriterC.flush();
}
count++;
Thread.sleep(500);
t2Condition.signal();
} else {
t1Condition.await();
}
} catch (Exception e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
}
static class PrintT2Thread implements Runnable {
BufferedWriter bufferedWriterA ;
BufferedWriter bufferedWriterB ;
BufferedWriter bufferedWriterC ;
@Override
public void run() {
while (true){
lock.lock();
try {
if (count % 3 == 1) {
bufferedWriterA.write("t2");
bufferedWriterB.write("t2");
bufferedWriterA.flush();
bufferedWriterB.flush();
if (count > 1) {
bufferedWriterC.write("t2");
bufferedWriterC.flush();
}
Thread.sleep(500);
count++;
t3Condition.signal();
} else {
t2Condition.await();
}
} catch (Exception e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
}
static class PrintT3Thread implements Runnable {
BufferedWriter bufferedWriterA ;
BufferedWriter bufferedWriterB ;
BufferedWriter bufferedWriterC ;
@Override
public void run() {
while (true){
lock.lock();
try {
if (count % 3 == 2) {
bufferedWriterA.write("t3");
bufferedWriterB.write("t3");
bufferedWriterC.write("t3");
bufferedWriterA.flush();
bufferedWriterB.flush();
bufferedWriterC.flush();
Thread.sleep(500);
count++;
t1Condition.signal();
} else {
t3Condition.await();
}
} catch (Exception e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
}
}
这题败在了对于IO文件流的类不熟悉。
下面开始第二题:
有三个线程,线程一只打印t1,线程二只打印t2,线程三只打印t3,在控制台上输出t1 t2 t3 。。循环5遍
之后输出t2 t3 t1。。5遍 再输出t3 t1 t2。。5遍之后就循环
这是我考完之后想到的:
/**
* 有三个线程,线程一只打印t1,线程二只打印t2,线程三只打印t3,在控制台上输出t1 t2 t3 。。循环5遍
* 之后输出t2 t3 t1。。5遍 再输出t3 t1 t2。。5遍之后就循环
*/
public class DemoTest4 {
private static volatile int count = 0;
private static volatile int signA = 0;
private static volatile int signB = 1;
private static volatile int signC = 2;
private static Object lock = new Object();
public static void main(String[] args) {
new Thread(new PrintT1Thread()).start();
new Thread(new PrintT2Thread()).start();
new Thread(new PrintT3Thread()).start();
}
static class PrintT1Thread implements Runnable{
@Override
public void run() {
while (true){
synchronized (lock){
try{
if (count % 3 == signA){
System.out.print("t1 ");
count++;
if (count % 15 == 0){
signA = (signA + 2) % 3;
signB = (signB + 2) % 3;
signC = (signC + 2) % 3;
}
lock.notifyAll();
}else {
lock.wait();
}
}catch (Exception e){
}
}
}
}
}
static class PrintT2Thread implements Runnable{
@Override
public void run() {
while (true){
synchronized (lock){
try{
if (count % 3 == signB){
System.out.print("t2 ");
count++;
if (count % 15 == 0){
signA = (signA + 2) % 3;
signB = (signB + 2) % 3;
signC = (signC + 2) % 3;
}
lock.notifyAll();
}else {
lock.wait();
}
}catch (Exception e){
}
}
}
}
}
static class PrintT3Thread implements Runnable{
@Override
public void run() {
while(true){
synchronized (lock){
try{
if (count % 3 == signC){
System.out.print("t3 ");
count++;
if (count % 15 == 0){
signA = (signA + 2) % 3;
signB = (signB + 2) % 3;
signC = (signC + 2) % 3;
}
lock.notifyAll();
}else {
lock.wait();
}
}catch (Exception e){
}
}
}
}
}
}
还有别人提供了一种其他思路:
/**
* 有三个线程,线程一只打印t1,线程二只打印t2,线程三只打印t3,在控制台上输出t1 t2 t3 。。循环5遍
* 之后输出t2 t3 t1。。5遍 再输出t3 t1 t2。。5遍之后就循环
*/
public class DemoTest3 {
public static void main(String[] args) {
for (int i = 1; i <=4 ; i++) {
for (int j = 0; j < 5; j++) {
NumberThread n = new NumberThread();
n.state = i;
Thread t1 = new Thread(n);
t1.setName("t1");
Thread t2 = new Thread(n);
t2.setName("t2");
Thread t3 = new Thread(n);
t3.setName("t3");
t1.start();
t2.start();
t3.start();
try{
Thread.sleep(500);
System.out.println();
}catch (Exception e){
}
}
if (i == 3){
i = 0;
}
}
}
static class NumberThread implements Runnable{
private int state;
private int count = 0;
@Override
public void run() {
while (true){
synchronized (this){
if (count == 3){
break;
}
String name = Thread.currentThread().getName();
if (name.contains(state + "")){
System.out.print(name);
count++;
state++;
}else {
try{
wait();
}catch (Exception e){
}
}
if (state == 4){
state = 1;
}
notifyAll();
if (count == 3){
break;
}
}
}
}
}
}
感觉还是败在了平时太过于依赖IDEA自动补全了,使用txt编程刚开始心态就有点问题了。继续努力,再战阿里~~~