`

多线程简单设计

阅读更多
线程直接的通信:通过管道流进行简单的交互
public class ThreadDemo6 {
	public static void main(String[] args) {
		PipedOutputStream pos=null;
		PipedInputStream pis=null;
		try {
			pos=new PipedOutputStream();
			pis=new PipedInputStream(pos);
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		Sender sender=new Sender(pos);
		Thread t1=new Thread(sender);
		Receiver receiver=new Receiver(pis);
		Thread t2=new Thread(receiver);
		t1.start();
		t2.start();
		
	}
}

class Sender implements Runnable {
	private OutputStream out;

	public Sender(OutputStream out) {
		super();
		this.out = out;
	}

	@Override
	public void run() {
		for (int i = 1; i <= 5; i++) {
			byte value = (byte) (Math.random() * 100);
			System.out.println("send value is " + value);
			try {
				out.write(value);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}

class Receiver implements Runnable {
	private InputStream in;

	public Receiver(InputStream in) {
		super();
		this.in = in;
	}

	@Override
	public void run() {
		for (int i = 1; i <= 5; i++) {
			try {
				byte value = (byte) in.read();
				System.out.println("receiver value is " + value);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}

有一个弊端就是在所有的数据写完后才能去读取,这样在写的时候一直占用内存,我们希望每写一点就能拿一点。看下边的实现:

线程直接的通信:使用Thread.yield()模拟一个生产者和消费者的模型
* 效率还是比较差。yield方法是主动放弃了cpu,又去竞争。
public class ThreadDemo7 {
	public static void main(String[] args) {
		FlagSend flagSend = new FlagSend();
		FlagRec flagRec = new FlagRec(flagSend);
		Thread t1 = new Thread(flagSend);
		Thread t2 = new Thread(flagRec);
		t1.start();
		t2.start();

	}
}

class FlagSend implements Runnable {
	int theValue;
	boolean flag;//是否有食物:true有食物

	@Override
	public void run() {
		for (int i = 1; i <= 5; i++) {
			while (flag) {
				Thread.yield();
			}
			theValue = new Random().nextInt(1000);// 制造食物
			System.out.println("send value is " + theValue);
			flag = true;// 等待食客去吃
		}
	}
}

class FlagRec implements Runnable {

	public FlagRec(FlagSend flagSend) {
		super();
		this.flagSend = flagSend;
	}
	private FlagSend flagSend;

	@Override
	public void run() {
		for (int i = 1; i <= 5; i++) {
			while (!flagSend.flag) {
				Thread.yield();
			}
			System.out.println("receiver value is " + flagSend.theValue);
			flagSend.flag = false;
		}
	}

}

yield方法是主动放弃了cpu,又去竞争。效率比较差,接收的人不知道是否send已经Ok了。我们希望我们发送以后就去提醒接收者去拿不是一直去在放弃。

线程直接的通信:wait/notify 任何一个对象都拥有一个线程等待池
* 挂在同一个对象的线程等待池中的线程之间可以互相唤醒 wait/notify是属于Object类的
* wait方法必须放入synchronized同步块中

/**
 * @author Janle
 *
 */
public class ThreadDemo8 {
	public static void main(String[] args) {
		Cooker cooker=new Cooker();
		Diners diners=new Diners(cooker);
		Thread t1=new Thread(cooker);
		Thread t2=new Thread(diners);
		//当程序只有守护线程时候程序退出。
		t2.setDaemon(true);
		t1.start();
		t2.start();
		
	}
}

class Cooker implements Runnable {
	boolean hasFood;
	int value;

	@Override
	public void run() {
		for (int i = 1; i <= 5; i++) {
			// 将锁挂到同一个线程等待池中
			synchronized (this) {
				try {
					while (hasFood) {// 使用while是因为存在虚假唤醒,不能使用if
						/**
						 * 在没有被通知、中断或超时的情况下,线程还可以唤醒一个所谓的虚假唤醒 (spurious wakeup)。
						 * 虽然这种情况在实践中很少发生,但是应用程序必须通过以下方式防止其发生,
						 * 即对应该导致该线程被提醒的条件进行测试, 如果不满足该条件,则继续等待。换句话说,等待应总是发生在循环中
						 */
						this.wait();//wait方法会释放钥匙
					}
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				value = new Random().nextInt(1000);
				System.out.println("Cooker 生产食物 " + value);
				hasFood=true;
				this.notify();
			}
		}
	}
}

class Diners implements Runnable {
	private Cooker cooker;

	public Diners(Cooker cooker) {
		super();
		this.cooker = cooker;
	}

	@Override
	public void run() {
		for (;;) {
			// 将锁挂到同一个线程等待池中
			synchronized (cooker) {
				try {
					while(!cooker.hasFood){
						cooker.wait();
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
				System.out.println("Diners 消费食物 " + cooker.value);
				cooker.hasFood=false;
				cooker.notify();
			}
			
		}
	}
}


线程中的通讯:在实际的业务中的使用
public class ThreadDemo9 {
	public static void main(String[] args) {
		final Bussiness bus=new Bussiness();
		Thread t1=new Thread(new Runnable() {
			@Override
			public void run() {
				bus.send();
			}
		});
		Thread t2=new Thread(new Runnable() {
			@Override
			public void run() {
				bus.recived();
			}
		});t2.setDaemon(true);
		t1.start();
		t2.start();
	}
}

class Bussiness {
	boolean flag;
	int value;

	public void send() {
		for (int i = 0; i < 5; i++) {
			synchronized (this) {
				try {
					while (flag) {
						this.wait();
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
				value = new Random().nextInt(1000);
				System.out.println("send value is " + value);
				flag = true;
				this.notify();
			}
		}
	}

	public void recived() {
		while (true) {
			synchronized (this) {
				try {
					while (!flag) {
						this.wait();
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
				System.out.println("receive value is " + value);
				flag = false;
				this.notify();
			}
		}
	}
}

一个在处理缓存时候超级实用的例子
/*
 * @author vayne
 * 
 * 多线程实现缓存的小demo
 */
class Cachend
{
    volatile Map<String, String> cachmap = new HashMap<String, String>();//加volatile关键字保证可见性。

    ReadWriteLock rwLock = new ReentrantReadWriteLock();//这个读写锁要定义在方法外面,使得每一个线程用的是同一个读写锁。
    public  String getS(String key)                     //如果定义在方法内部,就是跟方法栈有关的读写锁。这样可能不是同一个锁。
    {
        rwLock.readLock().lock();
        String value = null;
        try
        {
            value = cachmap.get(key);

            if (cachmap.get(key) == null)//这里要重新获得key对应的value值
            {
                rwLock.readLock().unlock();
                rwLock.writeLock().lock();
                try
                {
                    if (cachmap.get(key) == null)//这里也是
                    {
                        value = "" + Thread.currentThread().getName();

                        cachmap.put(key, value);

                        System.out.println(Thread.currentThread().getName()  + "  put the value ::::" + value);
                    }
                } finally
                {
                    rwLock.readLock().lock();   //将锁降级,这里跟下一句的顺序不能反。
                    rwLock.writeLock().unlock();//关于这里的顺序问题,下面我会提到。
                }
            }

        } finally
        {
            rwLock.readLock().unlock();
        }

        return cachmap.get(key);
    }
}

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics