作为一个android开发者的我来说,面试最怕问的问题就是问多线程方面的,问之必死~~。因为android monkey在开发中多线程开发的场景使用起来几乎没有,所以就滋生了自己的懒惰性,人家说哪里跌倒哪里爬起来,这工作几年了也没爬起来,有点小羞愧。于是准备抽点时间好好研究下这个东东。
不要逼我,逼急了我什么都能做出来! 来来来,现场手写一个自旋锁出来试试!卒!
在多线程的编程中,如果需要加锁的情况下,通常需要synchronized来搞定(当然这是最初级的用法)用来确保线程安全,比如HashTable这个在开发中没怎么用过的组件,看其源码可以发现其public方法都加了synchronized来搞定;所以说HashTable是线程安全的。
在我们处理多线程并发的时候可能会经常这么写(这也是wait和notify notify All的正确使用姿势):
Object lock = new Object();
synchronized (lock) {
while (condition is not ok) { // 条件不满足,当前线程阻塞等待
lock.wait();
}
// 执行条件满足时的逻辑
doSomething();
// 通知阻塞的线程可以唤醒
lock.notify();
}
简单举一个例子来说明,以前博主面试遇到过这个问题:两个线程交替打印奇数和偶数。
思路也很简单,因为是线程交替执行,所以当前数字是偶数的时候就让奇数线程wait,当前数字是奇数的时候就让偶数线程wait
打印奇数的线程
private Object lock = new Object();
private int i = 0;
// 打印奇数
class PrintOdd implements Runnable {
@Override
public void run() {
synchronized (lock) {
while (i <= 40) {
if (i % 2 == 1) {
System.out.println("打印奇数==" + i);
i++;
//通知偶数线程工作
lock.notify();
} else {
//当前是偶数,线程等待
try {
lock.wait();
} catch (InterruptedException e) {
}
}
} // end while
} // end synchronized
}//end run
}
打印偶数线程:
class PrintEven implements Runnable {
@Override
public void run() {
synchronized (lock) {
while (i <= 40) {
if (i % 2 == 0) {
System.out.println("打印偶数************ " + i);
i++;
//通知奇数线程
lock.notify();
} else {
try {
lock.wait();
} catch (InterruptedException e) {
}
}
} // end while
} // end synchronized
}//end run
}
上面就是简单的利用了wait和notify方法,其实还有一个更简单的写法,如下所示:
volatile boolean printOdd=true;
private int i=0;
// 打印奇数
class PrintOdd implements Runnable {
@Override
public void run() {
while(i<40) {
if(printOdd) {
System.out.println("打印奇数---------------"+i);
i++;
//开始打印偶数
printOdd=false;
}
}
}
}
class PrintEven implements Runnable {
@Override
public void run() {
while(i<40) {
if(!printOdd) {
System.out.println("打印偶数*********"+ i);
i++;
//开始打印奇数
printOdd=true;
}
}
}// end run
}
甚至可以把上面的i用AtomicInteger来替换,那么代码就如下所示:
volatile boolean printOdd=true;
private AtomicInteger i=new AtomicInteger();
// 打印奇数
class PrintOdd implements Runnable {
@Override
public void run() {
while(i.get()<4000) {
if(printOdd) {
System.out.println("打印奇数---------------"+i.getAndIncrement());
//开始打印偶数
printOdd=false;
}
}
}
}
class PrintEven implements Runnable {
@Override
public void run() {
while(i.get()<4000) {
if(!printOdd) {
System.out.println("打印偶数*********"+ i.getAndIncrement());
//开始打印奇数
printOdd=true;
}
}
}// end run
}