java线程同步及通信Demo——传统的线程通信

打开了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 = {"","","",""};

而锁的部分依然想使用buffer[i%4],变成这样:

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的具体用法就可以知道了!



你可能感兴趣的:(工作之前的随笔,通信,并行处理,多线程,Java,synchronized)