日期:2014-05-20  浏览次数:20838 次

结果不对亚?一个简单短小的例子——采用信号量和同步方法使发送线程与接收线程同步运行
一个缓冲区类BufferLock采用synchronized同步方法,一个发送线程Sender,一个接收线程Receiver,运行结果都不一致,偶尔才对,问题出在哪里呢?运行结果有时是:
Sender put: 1
 Receiver get: 1
 Receiver get: 2
Sender put: 2
Sender put: 3
 Receiver get: 3
Sender put: 4
 Receiver get: 4
Sender put: 5
 Receiver get: 5

public class BufferLock 
{
private int value;
private boolean isEmpty=true;
public synchronized void put(int i)
{
while(!isEmpty)
try
{
this.wait();
}
catch(InterruptedException e){}
value=i;
isEmpty=false;
notify();
}
public synchronized int get()
{
while(isEmpty)
try
{
this.wait();
}
catch(InterruptedException e){}
isEmpty=true;
notify();
return value;
}
}
class Sender extends Thread
{
private BufferLock buffer;
public Sender(BufferLock buffer)
{
this.buffer=buffer;
}
public void run()
{
for(int i=1;i<6;i++)
{
buffer.put(i);
System.out.println("Sender put: "+i);
}
}
}
class Receiver extends Thread
{
private BufferLock buffer;
public Receiver(BufferLock buffer)
{
this.buffer=buffer;
}
public void run()
{
for(int i=1;i<6;i++)
System.out.println("\t\t Receiver get: "+buffer.get());
}
public static void main(String args[])
{
BufferLock buffer=new BufferLock();
(new Sender(buffer)).start();
(new Receiver(buffer)).start();
}
}



------解决方案--------------------
锁共享的对象,也就是“buffer”对象。
public class BufferLock {
public static void main(String args[]) {
BufferLock buffer = new BufferLock();
(new Sender(buffer)).start();
(new Receiver(buffer)).start();
}

private int value;
private boolean isEmpty = true;

public void put(int i) {
while (!isEmpty)
try {
this.wait();
} catch (InterruptedException e) {
}
value = i;
isEmpty = false;
notify();
}

public int get() {
while (isEmpty)
try {
this.wait();
} catch (InterruptedException e) {
}
isEmpty = true;
notify();
return value;
}
}

class Sender extends Thread {
private BufferLock buffer;

public Sender(BufferLock buffer) {
this.buffer = buffer;
}

public void run() {
synchronized (buffer) {
for (int i = 1; i < 6; i++) {
buffer.put(i);
System.out.println("Sender put: " + i);
}
}
}
}

class Receiver extends Thread {
private BufferLock buffer;

public Receiver(BufferLock buffer) {
this.buffer = buffer;
}

public void run() {
synchronized (buffer) {
for (int i = 1; i < 6; i++)
System.out.println("\t\t Receiver get: " + buffer.get());
}
}

}
无论哪个线程锁了buffer,另外一个线程就只能wait了,直到noticy。也就不会出现多次receive或者多次sender的现象了。
------解决方案--------------------
1、synchronized锁定的是哪个对象呢?这个问题可以看这里:http://arthennala.blog.51cto.com/287631/56356,已经非常详细了。
2、它锁定的是调用这个同步方法对象。也就是说,当一个对象f1在不同的线程中执行这个同步方法时,它们之间会形成互斥,达到同步的效果。
new Thread(f1).start();
new Thread(f1).start();
为什么这个程序不行呢?
这个问题,只要关注下new Thread()里的参数啊。new Thread(f1).start();
new Thread(f1).start();这个是多个线程访问[color=#FF0000]同一个方法,所以锁方法对这两个线程是生效的。[/color],但你这个程序里,不是多个线程调用同一个方法啊,是2个线程都调用了不同的方法啊。
3、//会不会在这句语句执行之后还没return的时候发生线程调度了?
看这里http://www.blogjava.net/qileilove/archive/2011/09/22/359262.html。最主要是这句话:当一个被线程被唤醒 (notify)后,才会进入到就绪队列,等待cpu的调度,主要一句话就是:多线程里,CPU的线程调度我们控制不了。
------解决方案--------------------
把打印放在put、get方法内部就没问题了,同步锁锁的是get/put方法,而不是run的循环,会有问题。