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

来源:互联网 发布:阿里云与运营商云区别 编辑:程序博客网 时间:2024/05/24 07:32

打开了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;}@Overridepublic 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 blocke.printStackTrace();}}writer(i);isWritable[i%4] = false ;obj[index].notify();}}}}class Read implements Runnable{@Overridepublic 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 blocke.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]==0Thread[Thread-2,5,main]==2Thread[Thread-3,5,main]==3Thread[Thread-1,5,main]==1i ===0i ===1Thread[Thread-0,5,main]==4Thread[Thread-1,5,main]==5i ===2i ===3i ===4i ===5Thread[Thread-2,5,main]==6Thread[Thread-1,5,main]==9Thread[Thread-0,5,main]==8Thread[Thread-3,5,main]==7i ===6i ===7Thread[Thread-2,5,main]==10Thread[Thread-3,5,main]==11i ===8i ===9Thread[Thread-0,5,main]==12Thread[Thread-1,5,main]==13i ===10i ===11Thread[Thread-2,5,main]==14Thread[Thread-3,5,main]==15i ===12i ===13i ===14Thread[Thread-1,5,main]==17Thread[Thread-0,5,main]==16Thread[Thread-2,5,main]==18i ===15i ===16Thread[Thread-3,5,main]==19Thread[Thread-0,5,main]==20i ===17i ===18Thread[Thread-1,5,main]==21Thread[Thread-2,5,main]==22i ===19i ===20Thread[Thread-3,5,main]==23Thread[Thread-0,5,main]==24i ===21i ===22Thread[Thread-1,5,main]==25Thread[Thread-2,5,main]==26i ===23i ===24Thread[Thread-3,5,main]==27Thread[Thread-0,5,main]==28i ===25i ===26Thread[Thread-1,5,main]==29Thread[Thread-2,5,main]==30i ===27i ===28Thread[Thread-3,5,main]==31Thread[Thread-0,5,main]==32i ===29i ===30Thread[Thread-1,5,main]==33Thread[Thread-2,5,main]==34i ===31i ===32Thread[Thread-3,5,main]==35Thread[Thread-0,5,main]==36i ===33i ===34i ===35i ===36Thread[Thread-2,5,main]==38Thread[Thread-1,5,main]==37Thread[Thread-3,5,main]==39i ===37i ===38i ===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 blocke.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.IllegalMonitorStateExceptionat 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]==3Thread[Thread-1,5,main]==1Thread[Thread-2,5,main]==2Exception in thread "Thread-2" java.lang.IllegalMonitorStateExceptionat 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.IllegalMonitorStateExceptionat 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.IllegalMonitorStateExceptionat 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的具体用法就可以知道了!



原创粉丝点击