17.1. 截取字符串的函数
编程:编写一个截取字符串的函数,输入为一个字符串和字节数,输出为按字节截取的字符串。 但是要保证汉字不被截半个,如 我ABC,应该截为 我AB,输入 我ABC汉DEF,应该输出为 我ABC 而不是 我ABC+汉的半个。
17.2. 实现阻塞队列
这是一个相对艰难的多线程面试问题,它能达到很多的目的。第一,它可以检测侯选者是否能实际的用 Java 线程写程序;第二,可以检测侯选者对并发场景的理解,并且你可以根据这个问很多问题。如果他用 wait() 和 notify() 方法来实现阻塞队列,你可以要求他用最新的 Java 5 中的并发类来再写一次。
17.3. 解决生产者——消费者问题
与上面的问题很类似,但这个问题更经典,有些时候面试都会问下面的问题。在Java中怎么解决生产者——消费者问题,当然有很多解决方法,我已经分享了一种用阻塞队列实现的方法。有些时候他们甚至会问怎么实现哲学家进餐问题。
17.4. 如何跳出当前的多重嵌套循环
在 Java 中,要想跳出多重循环,可以在外面的循环语句前定义一个标号,然后在里层循环体的代码中使用带有标号的 break 语句,即可跳出外层循环。例如:
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
System.out.println(“i = ” + i + “, j = ” + j);
if (j == 5) break ok;
}
}
另外,我个人通常并不使用标号这种方式,而是让外层的循环条件表达式的结果可以受到里层循环体代码的控制,例如,要在二维数组中查找到某个数字。
int arr[][] = {
{
1,
2,
3
},
{
4,
5,
6,
7
},
{
9
}
};
boolean found = false;
for (int i = 0; i < arr.length && !found; i++) {
for (int j = 0; j < arr[i].length; j++) {
System.out.println(“i = ” + i + “, j = ” + j);
if (arr[i][j] == 5) {
found = true;
break;
}
}
}
17.5. 设计 4 个线程,其中两个线程每次对 j 增加 1,另外两个线程对 j 每次减少写出程序。
以下程序使用内部类实现线程,对 j 增减的时候没有考虑顺序问题。
public class ThreadTest1 {
private int j;
public static void main(String args[]) {
ThreadTest1 tt = newThreadTest1();
Inc inc = tt.new Inc();
Dec dec = tt.new Dec();
for (inti = 0; i < 2; i++) {
Thread t = newThread(inc);
t.start();
t = new Thread(dec);
t.start();
}
}
private synchronized void inc() {
j++;
System.out.println(Thread.currentThread().getName() + "-inc:" + j);
}
private synchronized void dec() {
j--;
System.out.println(Thread.currentThread().getName() + "-dec:" + j);
}
class Inc implements Runnable {
public void run() {
for (inti = 0; i < 100; i++) {
inc();
}
}
}
class Dec implements Runnable {
public void run() {
for (inti = 0; i < 100; i++) {
dec();
}
}
}
}
17.6. 子线程循环 10 次,接着主线程循环 100,接着又回到子线程循环 10 次,接着再回到主线程又循环 100,如此循环 50 次。
最终的程序代码如下:
public class ThreadTest {
/**
* @paramargs
*/
public static voidmain(String[] args) {
// TODO Auto-generated method stub
new ThreadTest().init();
}
public void init() {
final Business business = newBusiness();
new Thread(new Runnable() {
public voidrun() {
for (inti = 0; i < 50; i++) {
business.SubThread(i);
}
}
}).start();
for (int i = 0; i < 50; i++) {
business.MainThread(i);
}
}
private class Business {
booleanbShouldSub = true; //这里相当于定义了控制该谁执行的一个信号灯
public synchronized voidMainThread(int i) {
if (bShouldSub) try {
this.wait();
} catch(InterruptedException e) {
// TODO Auto-generatedcatch block
e.printStackTrace();
}
for (int j = 0; j < 5; j++) {
System.out.println(Thread.currentThread().getName() + ":i=" + i + ",j=" + j);
}
bShouldSub = true;
this.notify();
}
public synchronized voidSubThread(int i) {
if (!bShouldSub) try {
this.wait();
} catch(InterruptedExceptione) {
// TODO Auto-generatedcatch block
e.printStackTrace();
}
for (intj = 0; j < 10; j++) {
System.out.println(Thread.currentThread().getName() + ":i=" + i + ",j=" + j);
}
bShouldSub = false;
this.notify();
}
}
}
备注:不可能一上来就写出上面的完整代码,最初写出来的代码如下,问题在于两个线程的代码要参照同一个变量,即这两个线程的代码要共享数据,所以,把这两个线程的执行代码搬到同一个类中去:
package com.huawei.interview.lym;
public class ThreadTest {
private static booleanbShouldMain = false;
public static void main(String[] args) {
// TODO Auto-generated method stub
/*
new Thread() {
public void run() {
for (int i = 0; i < 50; i++) {
for (int j = 0; j < 10; j++) {
System.out.println("i=" + i + ",j=" + j);
}
}
}
}.start();
*/
// final String str = newString("");
new Thread(new Runnable() {
public voidrun() {
for (inti = 0; i < 50; i++) {
synchronized(ThreadTest.class) {
if (bShouldMain) {
try {
ThreadTest.class.wait();
} catch(InterruptedException e) {
e.printStackTrace();
}
}
for (intj = 0; j < 10; j++) {
System.out.println(Thread.currentThread().getName() + "i=" + i + ",j=" + j);
}
bShouldMain = true;
ThreadTest.class.notify();
}
}
}
}).start();
for (int i = 0; i < 50; i++) {
synchronized(ThreadTest.class) {
if (!bShouldMain) {
try {
ThreadTest.class.wait();
} catch(InterruptedException e) {
e.printStackTrace();
}
}
for (intj = 0; j < 5; j++) {
System.out.println(Thread.currentThread().getName() + "i=" + i + ",j=" + j);
}
bShouldMain = false;
ThreadTest.class.notify();
}
}
}
}
