oppx面试题
1、synchronized和Lock有什么區別?哪個可重入?哪個效率高?
synchronized是jdk的關鍵字,對應字節碼中monitorenter和monitorexit這兩個指令。當線程執行到monitorenter指令時,就嘗試去獲得鎖。如果獲得鎖,那么就執行同步代碼塊或者同步方法。如果不能獲取鎖,則線程會阻塞,直到獲取鎖,然后執行同步代碼塊或者同步方法。不用我們寫代碼手動釋放鎖,在同步代碼塊或者同步方法執行完畢或拋異常的情況下會自動釋放鎖。
Lock是jdk的一個接口,常用實現類是ReentrantLock。Lock有4個獲取鎖的方法:
void lock():鎖被另一個線程持有的話,當前線程會一直阻塞,直到獲取鎖。
void lockInterruptibly() throws InterruptedException:鎖被另一個線程持有的話,當前線程會一直阻塞,直到獲取鎖或者被其他線程中斷。
boolean tryLock():返回boolean類型。如果獲取到鎖的話,就返回true,否則返回false。線程不會阻塞。
boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException:鎖被另一個線程持有的話,當前線程會一直阻塞,直到獲取鎖或者到指定時間或者被其他線程中斷。
其實,只有tryLock()無參方法會直接返回,另外3個方法都會阻塞線程。
鎖不會自動釋放,即使拋異常,所以我們必須寫代碼手動釋放鎖。調用unlock()方法釋放鎖,且必須寫在finally塊中,防止拋異常而執行不到。
synchronized是非公平鎖。ReentrantLock既可以公平,又可以非公平,取決于構造器傳參,默認是非公平鎖,效率比公平鎖要高。公平鎖就是說獲得鎖的線程遵循先來后到的原則,而非公平鎖對線程先后順序無所謂。
ReentrantLock內部是用CAS實現的。在各種lock()方法中均調用了AQS的compareAndSetState()方法,而compareAndSetState()方法內部調用的是Unsafe(全類名是sun.misc.Unsafe)實例的CompareAndSwapInt()native方法。
2、CAS、AQS
CAS:compareAndSwap的簡稱,比較并替換,是實現并發算法時常用的一種技術。Doug Lea在實現AQS和原子類(AtomicInteger、AtomicBoolean等Atomic開頭的類)時,就大量使用了CAS。
CAS有3個操作數:當前內存值、預期值、要修改的新值。比較內存值和預期值,如果相等,就把值設為新值,返回true,否則什么都不做,返回false。
CAS最大的問題是ABA問題。CAS在操作值的時候會檢查下值有沒有發生變化,如果沒有發生變化則更新,但是如果一個值原來是A,變成了B,又變成了A,那么使用CAS進行檢查時會發現它的值沒有發生變化,但是實際上卻變化了。這就是CAS的ABA問題。常見的解決思路是使用版本號。在值前面追加上版本號,每次變量更新的時候把版本號加1,那么A-B-A 就會變成1A-2B-3A。目前在JDK的atomic包里提供了一個AtomicStampedReference類來解決ABA問題。這個類的compareAndSet方法作用是首先檢查當前引用是否等于預期引用,并且當前標志是否等于預期標志,如果全部相等,則以原子方式將該引用和該標志的值設置為給定的更新值。
i++是線程不安全的,AtomicInteger類的getAndIncrement()實例方法就可以替代并發情況下的i++,內部也是調用了Unsafe類的getAndAddInt()實例方法。
3、ConcurrentHashMap怎么實現的?
jdk1.6,ConcurrentHashMap采用了分段鎖技術。內部定義了一個繼承自ReentrantLock的Segment類。
Node是Map.Entry的子類,有4個成員變量分別是int hash、K key、volatile V val、volatile Node next。
jdk1.8,ConcurrentHashMap拋棄了原來的Segment分段鎖,而是采用了CAS+synchronized來保證并發安全性。ConcurrentHashMap不能存放key為null或者value為null的鍵值對,否則會拋NPE。
put方法實現:首先根據key的hashcode()方法及ConcurrentHashMap的spread()靜態方法,找到在Node數組中的位置。進入無限循環,先判斷Node數組是否為null或者長度是否等于0,如果是的話,就初始化Node數組,進入下一次循環。否則,從數組中找到對應位置的Node實例。如果該Node實例為null,則根據put方法的參數構造一個Node實例,并利用CAS寫入,內部是調用Unsafe的compareAndSwapObject()實例方法。如果成功,就跳出循環。否則,進入下一次循環。如果原Node實例不為null,則判斷其hash屬性值是否為-1,如果是,則數組擴容,進入下一次循環。否則,對Node實例加synchronized鎖,然后判斷新key是否等于Node實例的key(==或者equals方法返回true)以及新key對應的hash是否等于Node實例的hash。如果都相等,則說明是替換操作,用新的value替換Node實例的value。否則,把新Node實例賦值給老Node實例的next屬性。如果當前位置鏈表元素數量大于TREEIFY_THRESHOLD,則把鏈表轉成紅黑樹。
4、垃圾回收器有哪些?有什么不同?
?
5、postgresql相對于mysql有什么優點?
1)pg在GIS領域絕對領先。
2)pg支持窗口函數或者說是分析函數。而mysql直到8才支持,5.7及以前都不支持。
3)pg原生支持遞歸查詢,用with?recursive即可,而mysql沒那么簡單,需要自己寫存儲過程。
4)pg支持表達式索引和條件索引。mysq不支持。
表達式索引:
篩選條件是where lower(name) = 'zhangsan';
如果在name列上加索引,查詢語句肯定是不會走此索引的。所以可以給lower(name)加索引,腳本如下:
create index idx_lvl_trace_info_name_lower on lvl_trace_info(lower(name));
條件索引:
create index idx_lvl_trace_info_updated_date_2019 on lvl_trace_info(updated_date) where updated_date > '2019-01-01 00:00:00';
則下面語句會走索引
select * from lvl_trace_info where updated_date between '2019-01-01' and '2019-06-01';
而下面語句不會走索引
select * from lvl_trace_info where updated_date between '2018-01-01' and '2019-01-01';
5)pg還支持array、json、jsonb數據類型,還可以在json、jsonb類型數據的某些字段上建索引。mysql不支持。
create table pg_test (id serial primary key,hobbies text array,study_experience json,job_experience jsonb );insert into pg_test (hobbies, study_experience,job_experience) values?('{"dance","sing","football"}', '{"college": "sun yat-sen university", "middle school": "henan"}', '{"college": "sun yat-sen university", "middle school": "henan"}');
還可以在job_experienct列上的college建索引:
create index idx_pg_test_job_experience_college on pg_test using gin ((job_experience -> 'college'));
這樣,在查詢條件有college字段時,就可能會走索引:
select id, hobbies, study_experience, job_experience -> 'middle school' from pg_test where job_experience -> 'college' ? 'sun yat-sen university';
6)pg原生支持存儲emoji。而mysql需要指定字符集是utf8mb4,才能存儲emoji,否則會報如下格式錯誤
Incorrect string value: '\xF0\x9F\x98\x84' for column 'nick_name'。
在/etc/my.cnf添加如下內容,并且在建表時指定default charset=utf8mb4,就可以成功插入emoji了。
插入emoji sql語句:insert into wx_info (nick_name) values ('昵稱', '?sunshine');
character-set-server = utf8mb4 collation-server = utf8mb4_unicode_ci init_connect = 'SET NAMES utf8mb4' character-set-client-handshake = false7)有些開發人員喜歡用=null或者根本就分不清=null和is null,mysql數據庫只能用is null,用=null查不出數據。而pg為了包容開發人員的這個毛病,可以在postgresql.conf文件中把transform_null_equals設置成on,這樣用is null和=null都能查出數據了。當然不建議這么做。
8)mysql文本類型有tinytext、text、mediumtext、longtext,分別可支持不同長度的文本,在用的時候,需要我們預估文本長度,然后選擇一個合適的類型。而pg文本類型沒有那么多,只有一個text,可以支持任意長度,方便使用。
9)mysql可以通過select @@global.tx_isolation;及select @@tx_isolation;查看全局和當前會話的事務隔離級別。mysql的默認事務隔離級別是repeatable-read。
pg可以通過show default_transaction_isolation;及show transaction_isolation;查看默認事務隔離級別和當前會話事務隔離級別。pg的默認事務隔離是read committed(11版本,10版本的是,9版本的是)。
6、mysql主鍵索引和二級索引有什么區別?
InnoDB引擎的mysql,主鍵索引是聚簇索引,索引數據和行數據都存儲在同一個B+樹中。該B+樹根據索引數據進行創建,數據存儲在葉子節點中。數據的物理順序和索引邏輯順序一致。一個表最多只能有一個聚簇索引,因為數據物理順序不可能有多個順序。
二級索引,如普通索引、唯一索引、復合索引,是非聚簇索引。非聚簇索引,索引和數據分開存儲。索引B+樹只存儲索引數據及其與主鍵的映射。
舉個例子,表lvl_trace_info有主鍵字段id,普通索引字段updated_date,及其他。
根據主鍵id的查詢語句:
select * from lvl_trace_info where id = 99;
這個查詢語句會去主鍵索引樹上查數據,因為行數據存儲在葉子節點上,所以一下子就把數據查出來了。
根據普通索引列updated_date的查詢語句:
select * from lvl_trace_info where updated_date > current_date;
這個查詢語句會去updated_date對應的二級索引數上查找滿足updated_date > current_date的updated_date對應的主鍵id,然后再根據這些主鍵id去主鍵索引樹上查找對應的行數據??偨Y起來,需要先查詢二級索引樹,再查詢主鍵索引數。
7、mybatis一二級緩存。
mybatis一級緩存是SqlSession級別的。SqlSession是mybatis-xxx.jar包中的一個接口,全類名是org.apache.ibatis.session.SqlSession。在操作數據庫時需要構造SqlSession對象,查詢結果會保存到SqlSession對象中。如果下一次查詢還是用的此SqlSession對象,且查詢條件一樣,則不會去查數據庫,而是直接從SqlSession對象中取出數據,并返回。反之,如果每次查詢都是用的新的SqlSession對象,或是同一個SqlSession對象但查詢條件不一樣,或是同一個SqlSession對象但查詢之間穿插了增刪改,則一級緩存就用不上。增刪改操作會清空一級緩存數據。
mybatis二級緩存是多個SqlSession共享的。默認關閉,不建議使用。如果要使用的話,首先需要打開總開關,在mybatis的配置文件中添加
<settings> <!--開啟二級緩存--> <setting name="cacheEnabled" value="true"/> </settings>然后,哪個mapper想用二級緩存,就在哪個mapper下添加<cache />,具體是在<mapper namespace="xxx">下面添加<cache />。
如果二級緩存開啟的話,一條查詢語句會首先從二級緩存中查找數據,如果二級緩存沒有,則去一級緩存中查找數據,如果能拿到的話,就把數據放到二級緩存中,同時返回。如果一級緩存也沒有,則會去查庫,把查詢結果放到一級緩存、二級緩存中,并返回。
8、線上某接口響應慢,用什么工具或者方法定位問題?
?
9、從kafka的架構設計角度解釋一下kafka為什么能夠支持高并發?
?
10、spark reduceByKey、groupByKey有什么區別?常用的方法有哪些?
?
11、spark從kafka拉取數據有哪幾種方式?
利用KafkaUtils工具類(org.apache.spark.streaming.kafka.KafkaUtils,在spark-streaming-kafka-xxx.jar包中),有3種方式:
1)createDirectStream()一系列重載方法:
2)createStream()一系列重載方法:
3)createRDD()一系列重載方法:
轉載于:https://www.cnblogs.com/koushr/p/5873413.html
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
- 上一篇: linux启动和关闭
- 下一篇: 冒烟测试与回归测试的区别