Java线程并发同步问题

孙海峰VIP 2017-04-23 09:46:57
楼主最近在学JAVA多线程相关部分知识,遇到如下题目:
使用 wait notify 实现一个队列,队列有2个方法,add 和 get 。add方法往队列中添加元素,get方法往队列中获得元素。队列必须是线程安全的。如果get执行时,队列为空,线程必须阻塞等待,直到有队列有数据。如果add时,队列已经满,则add线程要等待,直到队列有空闲空间。

实现这么一个队列,并写一个测试代码,使他工作在多线程的环境下,证明,它的工作是正确的。给出程序和运行的截图。

下列代码单线程运行时正常,但在多线程执行下数据会混乱。
static ArrayQueue _queue = new ArrayQueue(10);
// static Object[] _queue = new Object[100];
static int index = 0;

@Test
public void test02() throws Exception {
// 使用 wait notify 实现一个队列,队列有2个方法,add 和 get
// 。add方法往队列中添加元素,get方法往队列中获得元素。队列必须是线程安全的。
// 如果get执行时,队列为空,线程必须阻塞等待,直到有队列有数据。如果add时,队列已经满,
// 则add线程要等待,直到队列有空闲空间。
//实现这么一个队列,并写一个测试代码,使他工作在多线程的环境下,证明,它的工作是正确的。给出程序和运行的截图。
Thread a1 = new Thread(new addThread(),"AddThread-1");
Thread a2 = new Thread(new addThread(),"AddThread-2");
Thread a3 = new Thread(new addThread(),"AddThread-3");
a1.start();
a2.start();
a3.start();
Thread g1 = new Thread(new getThread(), "GetThread-1");
Thread g2 = new Thread(new getThread(), "GetThread-2");
Thread g3 = new Thread(new getThread(), "GetThread-3");
g1.start();
g2.start();
g3.start();
a1.join();
a2.join();
a3.join();

g1.join();
g2.join();
g3.join();
}

static class ArrayQueue {
private Object[] _queue = new Object[10];
private int index = 0;
private int num = 0;

public ArrayQueue(int length) {
_queue = new Object[length];
}

public synchronized void add() {
_queue[index] = "Content-" + num++;
System.out.println("生产者:" + _queue[index]);
index++;
if (index > 0 && index < _queue.length) {
notify(); //唤醒消费
}
if (index == _queue.length) {
try {
wait(); //等待消费
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

public synchronized void get() {
Object rs = _queue[0]; //消费队列中第一个元素
System.out.println("消费者:" + rs);
Object[] temp = new Object[_queue.length];
System.arraycopy(_queue, 1, temp, 0, _queue.length - 1); //向前移动队列
_queue = temp;
index--;
if (index == 0) {
try {
wait(); // 等待生产
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (index == _queue.length - 1) {
notify(); //唤醒生产
}
}

}

class addThread implements Runnable {
// public addThread(String name) {
// super(name);
// }
@Override
public void run() {
while (true) {
_queue.add();
}
}
}

class getThread implements Runnable {
// public getThread(String name) {
// super(name);
// }

@Override
public void run() {
while (true) {
_queue.get();
}
}
}
...全文
341 4 打赏 收藏 转发到动态 举报
写回复
用AI写文章
4 条回复
切换为时间正序
请发表友善的回复…
发表回复
苍茫行者 2017-04-25
  • 打赏
  • 举报
回复
三个地方要修改: 1.将调用wait方法的if改为while,应该当对应线程被唤醒后,如果还是不能生产或消费,应该再次等待 2.将notify改为notifyAll,有多个生产者与消费者,如果是notify可能恰好只唤醒消费者(反过来也一样) 3.我修改了代码,你看看第三个改了哪里
public class App 
{
    static ArrayQueue _queue = new ArrayQueue(10);
    // static Object[] _queue = new Object[100];
    static int index = 0;
    public static void main(String[] args) throws InterruptedException {
        // 使用 wait notify 实现一个队列,队列有2个方法,add 和 get
        // 。add方法往队列中添加元素,get方法往队列中获得元素。队列必须是线程安全的。
        // 如果get执行时,队列为空,线程必须阻塞等待,直到有队列有数据。如果add时,队列已经满,
        // 则add线程要等待,直到队列有空闲空间。
        //实现这么一个队列,并写一个测试代码,使他工作在多线程的环境下,证明,它的工作是正确的。给出程序和运行的截图。
        Thread a1 = new Thread(new addThread(),"AddThread-1");
        Thread a2 = new Thread(new addThread(),"AddThread-2");
        Thread a3 = new Thread(new addThread(),"AddThread-3");
        a1.start();
        a2.start();
        a3.start();
        Thread g1 = new Thread(new getThread(), "GetThread-1");
        Thread g2 = new Thread(new getThread(), "GetThread-2");
        Thread g3 = new Thread(new getThread(), "GetThread-3");
        g1.start();
        g2.start();
        g3.start();
        a1.join();
        a2.join();
        a3.join();

        g1.join();
        g2.join();
        g3.join();
    }


    static class ArrayQueue {
        private Object[] _queue = new Object[10];
        private int index = 0;
        private int num = 0;

        public ArrayQueue(int length) {
            _queue = new Object[length];
        }

        public synchronized void add() {
            while (index == _queue.length) {
                try {
                    wait(); //等待消费
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            _queue[index] = "Content-" + num++;
            System.out.println("生产者:" + _queue[index]);
            index++;
                notifyAll(); //唤醒消费

        }

        public synchronized void get() {

            while (index == 0) {
                try {
                    wait(); // 等待生产
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            Object rs = _queue[0]; //消费队列中第一个元素
            System.out.println("消费者:" + rs);
            Object[] temp = new Object[_queue.length];
            System.arraycopy(_queue, 1, temp, 0, _queue.length - 1); //向前移动队列
            _queue = temp;
            index--;
            //唤醒生产
            notifyAll();

        }

    }

    static class addThread implements Runnable {
        //		public addThread(String name) {
//			super(name);
//		}
        @Override
        public void run() {
            while (true) {
                _queue.add();
            }
        }
    }

    static class getThread implements Runnable {
//		public getThread(String name) {
//			super(name);
//		}

        @Override
        public void run() {
            while (true) {
                _queue.get();
            }
        }
    }
}
烦死,一大早就来看代码,你也试着看看
孙海峰VIP 2017-04-25
  • 打赏
  • 举报
回复
已经调试好了,最终的修改比较大,我将元素操作的过程移到线程中去做了。以下是我修改后的代码并记了博客http://blog.csdn.net/shf4715/article/details/70624743
孙海峰VIP 2017-04-23
  • 打赏
  • 举报
回复
static ArrayQueue _queue = new ArrayQueue(10); // static Object[] _queue = new Object[100]; static int index = 0; @Test public void test02() throws Exception { // 使用 wait notify 实现一个队列,队列有2个方法,add 和 get // 。add方法往队列中添加元素,get方法往队列中获得元素。队列必须是线程安全的。 // 如果get执行时,队列为空,线程必须阻塞等待,直到有队列有数据。如果add时,队列已经满, // 则add线程要等待,直到队列有空闲空间。 //实现这么一个队列,并写一个测试代码,使他工作在多线程的环境下,证明,它的工作是正确的。给出程序和运行的截图。 Thread a1 = new Thread(new addThread(),"AddThread-1"); Thread a2 = new Thread(new addThread(),"AddThread-2"); Thread a3 = new Thread(new addThread(),"AddThread-3"); a1.start(); a2.start(); a3.start(); Thread g1 = new Thread(new getThread(), "GetThread-1"); Thread g2 = new Thread(new getThread(), "GetThread-2"); Thread g3 = new Thread(new getThread(), "GetThread-3"); g1.start(); g2.start(); g3.start(); a1.join(); a2.join(); a3.join(); g1.join(); g2.join(); g3.join(); } static class ArrayQueue { private Object[] _queue = new Object[10]; private int index = 0; private int num = 0; public ArrayQueue(int length) { _queue = new Object[length]; } public synchronized void add() { _queue[index] = "Content-" + num++; System.out.println("生产者:" + _queue[index]); index++; if (index > 0 && index < _queue.length) { notify(); //唤醒消费 } if (index == _queue.length) { try { wait(); //等待消费 } catch (InterruptedException e) { e.printStackTrace(); } } } public synchronized void get() { Object rs = _queue[0]; //消费队列中第一个元素 System.out.println("消费者:" + rs); Object[] temp = new Object[_queue.length]; System.arraycopy(_queue, 1, temp, 0, _queue.length - 1); //向前移动队列 _queue = temp; index--; if (index == 0) { try { wait(); // 等待生产 } catch (InterruptedException e) { e.printStackTrace(); } } if (index == _queue.length - 1) { notify(); //唤醒生产 } } } class addThread implements Runnable { // public addThread(String name) { // super(name); // } @Override public void run() { while (true) { _queue.add(); } } } class getThread implements Runnable { // public getThread(String name) { // super(name); // } @Override public void run() { while (true) { _queue.get(); } } }
孙海峰VIP 2017-04-23
  • 打赏
  • 举报
回复
不能沉,自己顶。

62,615

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧