Java多线程(4)——线程通信

线程之间的关系是平等的,彼此之间并不存在任何依赖,它们各自竞争CPU资源,互不相让,并且还无条件地阻止其他线程对共享资源的异步访问。然而,也有很多现实问题要求不仅要同步的访问同一共享资源,而且线程间还彼此牵制,通过相互通信来向前推进。那么,多个线程之间是如何进行通信的呢?

参考资料:Java程序中的多线程http://www.ibm.com/developerworks/cn/java/multithreading/

为什么会排队等待?

下面的这个简单的 Java 程序完成四项不相关的任务。这样的程序有单个控制线程,控制在这四个任务之间线性地移动。此外,因为所需的资源 ― 打印机、磁盘、数据库和显示屏 -- 由于硬件和软件的限制都有内在的潜伏时间,所以每项任务都包含明显的等待时间。因此,程序在访问数据库之前必须等待打印机完成打印文件的任务,等等。如果您正在等待程序的完成,则这是对计算资源和您的时间的一种拙劣使用。改进此程序的一种方法是使它成为多线程的。

class myclass {
static public void main(String args[]) {
    print_a_file();
    manipulate_another_file();
    access_database();
    draw_picture_on_screen();
    }
}

线程也称为轻型进程 (LWP)。因为线程只能在单个进程的作用域内活动,所以创建线程比创建进程要廉价得多。这样,因为线程允许协作和数据交换,并且在计算资源方面非常廉价,所以线程比进程更可取。(线程需要操作系统的支持,因此不是所有的机器都提供线程。)

线程组
线程是被个别创建的,但可以将它们归类到 线程组中,以便于调试和监视。只能在创建线程的同时将它与一个线程组相关联。在使用大量线程的程序中,使用线程组组织线程可能很有帮助。可以将它们看作是计算机上的目录和文件结构。

线程间通信
当线程在继续执行前需要等待一个条件时,仅有 synchronized 关键字是不够的。虽然 synchronized 关键字阻止并发更新一个对象,但它没有实现线程间通信 。Object 类为此提供了三个函数:wait()、notify() 和 notifyAll()。以全球气候预测程序为例。这些程序通过将地球分为许多单元,在每个循环中,每个单元的计算都是隔离进行的,直到这些值趋于稳定,然后相邻单元之间就会交换一些数据。所以,从本质上讲,在每个循环中各个线程都必须等待所有线程完成各自的任务以后才能进入下一个循环。

wait():让线程处于冻结状态,被wait的线程会被存储到线程池中;

notify():唤醒线程池中的任意一个线程;

notifyAll():唤醒线程池中的所有线程。

这些方法都必须定义在同步中。


下面是一个简单的线程间通信案例:输入/输出的通信

class Resource{
	 String name;
	 String sex;
	boolean flag = false;
}

class Input implements Runnable{
	Resource r;
	Input(Resource r){
		this.r = r;
	}
	//这里的synchronized同步代码块可以封装到Resource类中作为一个synchronized函数
	public void run(){
		int x=0;
		while(true){
			synchronized(r){
				if(r.flag){
					try{
						r.wait();
					}catch(InterruptedException e){
						//e.printStack();
						}
				}
				if(x==0){
					r.name="woca";
					r.sex="male";
				}else{
					r.name="wori";
					r.sex="female";
				}
				
				r.flag = true;
				r.notify();
			}
			x = (x+1)%2;
		}
	}
}

class Output implements Runnable{
		Resource r;
		Output(Resource r){
				this.r = r;
			}
		public void run(){
				while(true){
						synchronized(r){
								if(!r.flag){
										try{
												r.wait();
											}catch(InterruptedException e){
													//e.printStack();
												}
									}
								System.out.println(r.name+"...."+r.sex);
								r.flag = false;
								r.notify();
							}
					}
			}
}

class ResourceDemo{
		public static void main(String[] args){
				Resource r = new Resource();
				Input in = new Input(r);
				Output out = new Output(r);
				Thread t1 = new Thread(in);
				Thread t2 = new Thread(out);
				t1.start();
				t2.start();
			}
	}


wait 和 sleep 区别?

1.wait可以指定时间也可以不指定。

   sleep必须指定时间。

2.在同步中时,对cpu的执行权和锁的处理不同。

wait:释放执行权,释放锁。
sleep:释放执行权,不释放锁。


调试大量的线程,需要我们对每个线程进行状态判断

public class Probe extends Thread {
    public Probe() {}
    public void run() {
        while(true) {
            Thread[] x = new Thread[100];
            Thread.enumerate(x);
            for(int i=0; i<100; i++) {
            Thread t = x[i];
            if(t == null)
                break;
            else
                System.out.println(t.getName() + "\t" + t.getPriority()
                + "\t" + t.isAlive() + "\t" + t.isDaemon());
            }
        }
    }
}


限制线程优先级和调度

Java 线程模型涉及可以动态更改的线程优先级。本质上,线程的优先级是从 1 到 10 之间的一个数字,数字越大表明任务越紧急。JVM 标准首先调用优先级较高的线程,然后才调用优先级较低的线程。但是,该标准对具有相同优先级的线程的处理是随机的。如何处理这些线程取决于基层的操作系统策略。在某些情况下,优先级相同的线程分时运行;在另一些情况下,线程将一直运行到结束。请记住,Java 支持 10 个优先级,基层操作系统支持的优先级可能要少得多,这样会造成一些混乱。因此,只能将优先级作为一种很粗略的工具使用。最后的控制可以通过明智地使用 yield() 函数来完成。通常情况下,请不要依靠线程优先级来控制线程的状态。







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值