目录: StringBuffer和StringBuilder有什么区别?假设有一个方法,方法内部需要定义一个对象,可能是StringBuffer或StringBuilder,接下来会多次append
目录:
StringBuffer和StringBuilder有什么区别?假设有一个方法,方法内部需要定义一个对象,可能是StringBuffer或StringBuilder,接下来会多次append操作,方法结束时,返回这个对象的toString()结果,并且这个线程会被多线程并发访问,请选择这个对象是被定义成StringBuffer或者StringBuilder?为什么?
synchronized有什么用?如何使用?(伪代码,把所有使用方式都分别列出来)
ReentranLock类有什么作用?它常用的方法有哪几个?分别有什么特点?
集群环境下多机器间进行同步操作有什么可选的解决方案?(最好用伪代码写出关键部分)
列出乐观锁的设计要点和使用方法?
何为幂等性控制?举一个例子说明你之前如何实现幂等性控制?(或在项目IDCM中如何实现幂等性控制?)
spring实现aop用到的关键技术是什么?
HashMap和ConcurrentHashMap有什么区别和特点?
java.util.concurrent package下,你用过哪些类?分别有什么用途和特点?
如果一张表数据量较大,影响了查询性能,可以有哪些优化方案?建立索引有什么原则?
说一说数据库事务隔离级别的理解?(项目IDCM中是如何使用的?)
Spring中注解@Component @Repository @Service @Controller的区别?(项目IDCM中context:component-scan注解扫描是如何配置的?)
1.StringBuffer和StringBuilder有什么区别?假设有一个方法,方法内部需要定义一个对象,可能是StringBuffer或StringBuilder,接下来会多次append操作,方法结束时,返回这个对象的toString()结果,并且这个线程会被多线程并发访问,请选择这个对象是被定义成StringBuffer或者StringBuilder?为什么?
答:StringBuffer是线程安全的;StringBuilder是线程不安全的。
复制代码
1.先来看String StringBuffer StringBuilder定义。final修饰的类不能被继承,即不能拥有子类。
public final class StringBuffer
public final class StringBuilder
public final class String
2.关于appdend方法的源码如下:
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}
public StringBuilder append(String str) {
super.append(str);
return this;
}
3.对于经常变动的字符串才会考虑使用StringBuilder和StringBuffer,使用StringBuilder效率比StringBuffer高,StringBuffer可以保证线程安全,而StringBuilder不能。
复制代码
2.synchronized有什么用?如何使用?(伪代码,把所有使用方式都分别列出来)
答:synchronized是Java语言的关键字,同时也是一个可重入锁。当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。synchronized用于修饰方法和代码块。
复制代码
package basic;public final class TestSynchronized { public static void main(String[] args) { new Thread("线程A") {
@Override public void run() { try {
print("线程A ...");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start(); new Thread("线程B") {
@Override public void run() { try {
print("线程B ...");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
} public static synchronized void print(String str) throws InterruptedException {
System.out.println("当前线程:" + Thread.currentThread().getName() + "执行开始"); for (int i = 0; i < 10; i++) {
System.out.println(str);
Thread.sleep(2000);
}
System.out.println("当前线程:" + Thread.currentThread().getName() + "执行完毕");
}
}
// 代码执行结果:
//当前线程:线程A执行开始
//线程A ...
//线程A ...
//线程A ...
//线程A ...
//线程A ...
//线程A ...
//线程A ...
//线程A ...
//线程A ...
//线程A ...
//当前线程:线程A执行完毕//当前线程:线程B执行开始
//线程B ...
//线程B ...
//线程B ...
//线程B ...
//线程B ...
//线程B ...
//线程B ...
//线程B ...
//线程B ...
//线程B ...
//当前线程:线程B执行完毕
复制代码
synchronized在修饰方法的同时,还可以修饰代码块,示例代码如下:
复制代码
package basic;public class SynchronizedExample { public static void main(String[] args) { new Thread("线程A") {
@Override public void run() {
print("线程A");
}
}.start(); new Thread("线程B") {
@Override public void run() {
print("线程B");
}
}.start();
} public static void print(String str) {
System.out.println("线程: " + Thread.currentThread().getName() + "开始执行"); synchronized (SynchronizedExample.class) { for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "打印了信息:" + i); try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
}
System.out.println("线程: " + Thread.currentThread().getName() + "执行结束");
}
}// 代码执行结果:// 线程: 线程A开始执行// 线程A打印了信息:0// 线程: 线程B开始执行// 线程A打印了信息:1// 线程A打印了信息:2// 线程A打印了信息:3// 线程A打印了信息:4// 线程A打印了信息:5// 线程A打印了信息:6// 线程A打印了信息:7// 线程A打印了信息:8// 线程A打印了信息:9// 线程: 线程A执行结束// 线程B打印了信息:0// 线程B打印了信息:1// 线程B打印了信息:2// 线程B打印了信息:3// 线程B打印了信息:4// 线程B打印了信息:5// 线程B打印了信息:6// 线程B打印了信息:7// 线程B打印了信息:8// 线程B打印了信息:9// 线程: 线程B执行结束
复制代码
接下来详细说明synchronized在修饰方法的时候的细节。synchronized是对类的当前实例进行加锁,防止其他线程同时访问该类的该实例的所有synchronized块,注意这里是“类的当前实例”,类的两个不同实例就没有这种约束了。那么static synchronized恰好就是要控制类的所有实例的访问了,static synchronized是限制线程同时访问jvm中该类的所有实例同时访问对应的代码快。实际上,在类中某方法或某代码块中有synchronized,那么在生成一个该类实例后,该类也就有一个监视快,放置线程并发访问改实例synchronized保护快,而static synchronized则是所有该类的实例公用一个监视快了,也就是两个的区别了,也就是synchronized相当于this.synchronized,而static synchronized相当于Something.synchronized。
复制代码
package basic;public class SynchronizedExample { public static void main(String[] args) { final MySynchronized mySynchronized = new MySynchronized(); new Thread("线程A") {
@Override public void run() {
mySynchronized.print("线程A");
}
}.start(); new Thread("线程B") {
@Override public void run() {
mySynchronized.print("线程B");
}
}.start();
}
}class MySynchronized { public synchronized void print(String str) {
System.out.println("线程: " + Thread.currentThread().getName() + "开始执行"); for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "打印了信息:" + i); try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
System.out.println("线程: " + Thread.currentThread().getName() + "执行结束");
}
}
// 代码运行结果:
//线程: 线程A开始执行
//线程A打印了信息:0
//线程A打印了信息:1
//线程A打印了信息:2
//线程A打印了信息:3
//线程A打印了信息:4
//线程A打印了信息:5
//线程A打印了信息:6
//线程A打印了信息:7//线程A打印了信息:8
//线程A打印了信息:9
//线程: 线程A执行结束
//线程: 线程B开始执行
//线程B打印了信息:0
//线程B打印了信息:1
//线程B打印了信息:2
//线程B打印了信息:3
//线程B打印了信息:4
//线程B打印了信息:5//线程B打印了信息:6
//线程B打印了信息:7
//线程B打印了信息:8
//线程B打印了信息:9
//线程: 线程B执行结束 package basic;public class SynchronizedExample { public static void main(String[] args) { final MySynchronized mySynchronized_first = new MySynchronized(); final MySynchronized mySynchronized_second = new MySynchronized(); new Thread("线程A") {
@Override public void run() {
mySynchronized_first.print("线程A");
}
}.start(); new Thread("线程B") {
@Override public void run() {
mySynchronized_second.print("线程B");
}
}.start();
}
}class MySynchronized { public synchronized void print(String str) {
System.out.println("线程: " + Thread.currentThread().getName() + "开始执行"); for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "打印了信息:" + i); try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
System.out.println("线程: " + Thread.currentThread().getName() + "执行结束");
}
}//代码运行结果:
//线程: 线程A开始执行
//线程A打印了信息:0
//线程: 线程B开始执行
//线程B打印了信息:0
//线程A打印了信息:1
//线程B打印了信息:1
//线程A打印了信息:2
//线程B打印了信息:2
//线程A打印了信息:3//线程B打印了信息:3
//线程A打印了信息:4
//线程B打印了信息:4
//线程A打印了信息:5
//线程B打印了信息:5
//线程A打印了信息:6
//线程B打印了信息:6
//线程A打印了信息:7
//线程B打印了信息:7
//线程A打印了信息:8//线程B打印了信息:8
//线程A打印了信息:9
//线程B打印了信息:9
//线程: 线程A执行结束
//线程: 线程B执行结束 package basic;public class SynchronizedExample { public static void main(String[] args) { final MySynchronized mySynchronized_first = new MySynchronized(); final MySynchronized mySynchronized_second = new MySynchronized(); new Thread("线程A") {
@Override public void run() {
mySynchronized_first.print("线程A");
}
}.start(); new Thread("线程B") {
@Override public void run() {
mySynchronized_second.print("线程B");
}
}.start();
}
}class MySynchronized { public static synchronized void print(String str) {
System.out.println("线程: " + Thread.currentThread().getName() + "开始执行"); for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "打印了信息:" + i); try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
System.out.println("线程: " + Thread.currentThread().getName() + "执行结束");
}
}//代码运行结果:
//线程: 线程A开始执行
//线程A打印了信息:0//线程A打印了信息:1
//线程A打印了信息:2
//线程A打印了信息:3
//线程A打印了信息:4
//线程A打印了信息:5
//线程A打印了信息:6
//线程A打印了信息:7//线程A打印了信息:8
//线程A打印了信息:9
//线程: 线程A执行结束
//线程: 线程B开始执行
//线程B打印了信息:0
//线程B打印了信息:1
//线程B打印了信息:2
//线程B打印了信息:3
//线程B打印了信息:4
//线程B打印了信息:5//线程B打印了信息:6
//线程B打印了信息:7
//线程B打印了信息:8
//线程B打印了信息:9
//线程: 线程B执行结束
复制代码
上述代码完整的展示了static synchronized和synchronized的用法。synchronized针对同一个实例不能访问,针对不同的实例可以同时访问。static synchronized针对所有的实例均不能同时访问。synchronized本来就是修饰方法的,后来引申出synchronized修饰代码块,只是为了可以更精确的控制冲突限制的访问区域,使得表现更加高效率。synchronized方法只能锁定现阶段的对象,而synchronized区块可以锁定指定的对象,指定的对象直接跟在synchronized()括号之后。此外,synchronized关键字是不能继承的,也就是说,基类的方法synchronized f(){} 在继承类中并不自动是synchronized f(){},而是变成了f(){}。继承类需要你显式的指定它的某个方法为synchronized方法。还有synchronized不能被继承,继承时子类的覆盖方法必须显示定义成synchronized。
除了方法前用synchronized关键字,synchronized关键字还可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问。用法是: synchronized(object){/*区块*/},它的作用域是object对象。当一个线程执行时,将object对象锁住,另一个线程就不能执行对应的块。synchronized方法实际上等同于用一个synchronized块包住方法中的所有语句,然后在synchronized块的括号中传入this关键字。当然,如果是静态方法,需要锁定的则是class对象。可能一个方法中只有几行代码会涉及到线程同步问题,所以synchronized块比synchronized方法更加细粒度地控制了多个线程的访问,只有synchronized块中的内容不能同时被多个线程所访问,方法中的其他语句仍然可以同时被多个线程所访问(包括synchronized块之前的和之后的)。
复制代码
package basic;public class TestSynchronizedObject { public static void main(String[] args) { final MyObject myObject_first = new MyObject(); final MyObject myObject_seconde = new MyObject(); new Thread("线程A") {
@Override public void run() {
myObject_first.print("线程A");
}
}.start(); new Thread("线程B") {
@Override public void run() { /* * 同一个实例,实现了互斥访问 */
myObject_first.print("线程B"); /* * 不同的实例,并不能够实现互斥访问 */
myObject_seconde.print("线程B");
}
}.start();
}
}class MyObject { /**
* * synchronized(this)的用法相当于synchronized直接修饰方法<br/>
* * 只针对一个实例的时候有效,针对多个实例的时候无效 */
public void print(String str) {
System.out.println("线程" + Thread.currentThread().getName() + "开始执行"); synchronized (this) { for (int i = 0; i < 10; i++) {
System.out.println(str + " ." + i + ". "); try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
}
System.out.println("线程" + Thread.currentThread().getName() + "执行结束");
}
}package basic;public class TestSynchronizedObject { public static void main(String[] args) { final MyObject myObject_first = new MyObject(); final MyObject myObject_seconde = new MyObject(); new Thread("线程A") {
@Override public void run() {
myObject_first.print("线程A");
}
}.start(); new Thread("线程B") {
@Override public void run() {
myObject_seconde.print("线程B");
}
}.start();
}
}class MyObject { /**
* * synchronized(MyObject.class)的用法相当于static synchronized修饰方法<br/>
* * 在针对多个实例的情况下,互斥有效,但是synchronized括号后面要指定正确的对象信息 */
public void print(String str) {
System.out.println("线程" + Thread.currentThread().getName() + "开始执行"); /*
* 1、synchronized(MyObjcet.class)可以正确的实现互斥效果 ,因为调用的是MyObject的对象。 */
synchronized (MyObject.class) { for (int i = 0; i < 10; i++) {
System.out.println(str + " ." + i + ". "); try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
}
System.out.println("线程" + Thread.currentThread().getName() + "执行结束");
}
}
复制代码
总结:synchronized方法是一种粗粒度的并发控制,在某一时刻,只能有一个线程执行该synchronized方法。synchronized块则是一种细粒度的鬓发控制,只会将块中的代码同步,位于方法内,synchronized块之外的代码是可以被多个线程同时访问到的。关于synchronized修饰代码块的详细细节可以参考附录[1]和附录[2]。
3.ReentrantLock类有什么作用?它常用的方法有哪几个?分别有什么特点?(读法:Re-entrantLock)
上面的的synchronized和ReentranLock是最经典的可重入锁,在面试中经常有问到两种锁的对比。先介绍ReentranLock的使用和代码示例,接着再分析ReentranLock和synchronized的具体区别。
4.集群环境下多机器间进行同步操作有什么可选的解决方案?(最好用伪代码写出关键部分)
reids
5.列出乐观锁的设计要点和使用方法?
6.何为幂等性控制?举一个例子说明你之前如何实现幂等性控制?(或在项目IDCM中如何实现幂等性控制?)
7.spring实现aop用到的关键技术是什么?
8.HashMap和ConcurrentHashMap有什么区别和特点?
9.java.util.concurrent package下,你用过哪些类?分别有什么用途和特点?
10.如果一张表数据量较大,影响了查询性能,可以有哪些优化方案?建立索引有什么原则?
11.说一说数据库事务隔离级别的理解?(项目IDCM中是如何使用的?)
12.Spring中注解@Component @Repository @Service @Controller的区别?(项目IDCM中context:component-scan注解扫描是如何配置的?)