打开了eclipse发现了前几天找工作时,做的一个面试题(那个题目是英文的,大概意思就是下面这些):
现在有一个大文件,需要加载进入内存中进行处理,要求如下:
1.内存有限,文件不能一次载入;2.使用多个线程并行处理:使用多线程载入文件,处理的时候要求按序处理。
Ps:题意就是要求多线程程序,然后cpu处理文件的时候要按照文件的本来顺序进行处理,就好像:4个线程把文件分块加载进来后变成 0 2 3 1,然后你处理的时候必须先处理0 ,然后是1 ,然后 是2 和 3 ……就这个意思。
今天看见了当时的代码 ,最近正好在看并发,就顺便多写了几个demo,下面就接着发上来。
下面这是一个相似的例子:
给定一个数组,通过4个线程向里面写数据,1个线程从其中往外按顺序读数据,4个线程每个线程都维持一个缓存区,各自负责各自的部分,互不干扰。这是通过传统的线程通信实现的(synchronized代码块加上wait和notify)
package com.thread.test;
public class ReadAndWrite {
static String[] buffer = new String[4];
// static Object obj = new Object();
static Object[] obj = {new Object(),new Object(),new Object(),new Object()};
static Boolean[] isWritable = {true,true,true,true};
public static void main(String[] args){
ReadAndWrite raw = new ReadAndWrite();
// Write w = raw.new Write();
Read r =raw.new Read();
for(int i=0 ;i <4 ;i++){
new Thread(raw.new Write(i)).start();
}
new Thread(r).start();
}
class Write implements Runnable{
int index = 0;
public Write(int i) {
index = i;
}
@Override
public void run() {
for(int i = index;i <40 ;i=i+4){
synchronized (obj[index]) {
while(!isWritable[i%4]){
try {
obj[index].wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
writer(i);
isWritable[i%4] = false ;
obj[index].notify();
}
}
}
}
class Read implements Runnable{
@Override
public void run() {
for(int i = 0 ; i<40;i++){
synchronized (obj[i%4]) {
while(isWritable[i%4]){
try {
obj[i%4].wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
read(i);
isWritable[i%4] = true ;
obj[i%4].notify();
}
}
}
}
static void writer(int i){
buffer[i%4] = "i ===" +i;
System.out.println(Thread.currentThread()+"=="+i);
}
static void read(int i){
System.out.println(buffer[i%4]);
}
}
输出结果如下:
Thread[Thread-0,5,main]==0
Thread[Thread-2,5,main]==2
Thread[Thread-3,5,main]==3
Thread[Thread-1,5,main]==1
i ===0
i ===1
Thread[Thread-0,5,main]==4
Thread[Thread-1,5,main]==5
i ===2
i ===3
i ===4
i ===5
Thread[Thread-2,5,main]==6
Thread[Thread-1,5,main]==9
Thread[Thread-0,5,main]==8
Thread[Thread-3,5,main]==7
i ===6
i ===7
Thread[Thread-2,5,main]==10
Thread[Thread-3,5,main]==11
i ===8
i ===9
Thread[Thread-0,5,main]==12
Thread[Thread-1,5,main]==13
i ===10
i ===11
Thread[Thread-2,5,main]==14
Thread[Thread-3,5,main]==15
i ===12
i ===13
i ===14
Thread[Thread-1,5,main]==17
Thread[Thread-0,5,main]==16
Thread[Thread-2,5,main]==18
i ===15
i ===16
Thread[Thread-3,5,main]==19
Thread[Thread-0,5,main]==20
i ===17
i ===18
Thread[Thread-1,5,main]==21
Thread[Thread-2,5,main]==22
i ===19
i ===20
Thread[Thread-3,5,main]==23
Thread[Thread-0,5,main]==24
i ===21
i ===22
Thread[Thread-1,5,main]==25
Thread[Thread-2,5,main]==26
i ===23
i ===24
Thread[Thread-3,5,main]==27
Thread[Thread-0,5,main]==28
i ===25
i ===26
Thread[Thread-1,5,main]==29
Thread[Thread-2,5,main]==30
i ===27
i ===28
Thread[Thread-3,5,main]==31
Thread[Thread-0,5,main]==32
i ===29
i ===30
Thread[Thread-1,5,main]==33
Thread[Thread-2,5,main]==34
i ===31
i ===32
Thread[Thread-3,5,main]==35
Thread[Thread-0,5,main]==36
i ===33
i ===34
i ===35
i ===36
Thread[Thread-2,5,main]==38
Thread[Thread-1,5,main]==37
Thread[Thread-3,5,main]==39
i ===37
i ===38
i ===39
Thread-0只负责加载了 4的倍数 4N,Thread-1只负责加载了 4N+1, Thread -2 只负责加载了 4N+2, Thread-3只负责加载了 4N+3,
并且这4个写的线程之间毫不影响,他们各自只和那一个读的线程互斥来往。
所以就给了四把锁Object[] ,分别用于各个写线程与唯一的一个读线程互斥。
上面的结果虽然一直都没有出错,不过我总感觉好像synchronized(obj)这里并没有锁住,只是由于这个题目的特性,所以没有发生错误而已……但是我试着用buffer[i%4]代替obj[i%4]……就直接报空指针异常,因为刚开始的数组是空着的……然后我把buffer[]数组直接给初始化了,变成这样:
static String[] buffer = {"","","",""};
synchronized (buffer[index]) { //buffer[index] obj[index]
while(!isWritable[i%4]){
try {
buffer[index].wait(); //buffer[index] obj[index]
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
writer(i);
isWritable[i%4] = false ;
buffer[index].notify();//buffer[index] obj[index]
}
Thread[Thread-0,5,main]==0Exception in thread "Thread-0" java.lang.IllegalMonitorStateException
at java.lang.Object.notify(Native Method)
at com.thread.test.ReadAndWrite$Write.run(ReadAndWrite.java:39)
at java.lang.Thread.run(Thread.java:619)
Thread[Thread-3,5,main]==3
Thread[Thread-1,5,main]==1
Thread[Thread-2,5,main]==2
Exception in thread "Thread-2" java.lang.IllegalMonitorStateException
at java.lang.Object.notify(Native Method)
at com.thread.test.ReadAndWrite$Write.run(ReadAndWrite.java:39)
at java.lang.Thread.run(Thread.java:619)
Exception in thread "Thread-1" java.lang.IllegalMonitorStateException
at java.lang.Object.notify(Native Method)
at com.thread.test.ReadAndWrite$Write.run(ReadAndWrite.java:39)
at java.lang.Thread.run(Thread.java:619)
Exception in thread "Thread-3" java.lang.IllegalMonitorStateException
at java.lang.Object.notify(Native Method)
at com.thread.test.ReadAndWrite$Write.run(ReadAndWrite.java:39)
at java.lang.Thread.run(Thread.java:619)
虽然感觉使用obj【】这个锁好像并没有起到锁的作用,只是用来通信而已,但是如果使用buffer【】本身的元素作为所对象的话,就直接报错了……
那么回头看的话 ,就是没有错了。 上面代码实际就是给每个缓存块 都绑定了一个锁obj ,还不了解原因的话 就得查下synchronized的具体用法就可以知道了!