`
leogao_emcom
  • 浏览: 81871 次
  • 性别: Icon_minigender_1
  • 来自: 大连
社区版块
存档分类
最新评论

有关Java 5.0+ 并发包的探讨-1 section

阅读更多

基础结构:
在Java的Thread体系中,最基础的就是Runnable接口,它代表了一个线程功能的“契约”,或者是线程的功能在Java中的表述,因为线程不是哪个语言的特有,而是操作系统的特有,所以这里就给予一个中性的描述“此接口就是一个线程功能在Java中的表述”,请看它在Java中声明的结构:

  public interface java.lang.Runnable {
  public void run();
  }


这类似Command设计模式,只提供一个方法抽象,代表所有的“命令”,这里也有这样的意思,也就是用这个接口就可以描述一个线程“想干什么”的问题,我们可以实现这个接口:

 
public class dosomethingThread implements Runnable {

	@Override
	public void run() {
		System.out.println("do somethings");
		
	}

}


这是一个正常的方式,还可以使用下面这样方式:

  public class ThreadBasicDemo {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		Runnable runnableInterface = new Runnable() {

			@Override
			public void run() {
				System.out.println("do somethings");

			}

		};

	}

}


有了想让线程做什么事情的“核”,接下来就应该把这个“核”包裹在一个真正的线程中了,在Java中,线程是用Thread类表示的,这个类包装了与操作系统交互而管理线程的逻辑,我们不用知道!不过喜欢探索的家伙可能还是喜欢看一看咋回事!所以我这里列出一个Thread的Start方法在JDK实现片段(一个线程是Start方法启动的):

  public synchronized void start() {
        /**
	 * This method is not invoked for the main method thread or "system"
	 * group threads created/set up by the VM. Any new functionality added 
	 * to this method in the future may have to also be added to the VM.
	 *
	 * A zero status value corresponds to state "NEW".
         */
        if (threadStatus != 0 || this != me)
            throw new IllegalThreadStateException();
        group.add(this);
        start0();
        if (stopBeforeStart) {
	    stop0(throwableFromStop);
	}
    }

    private native void start0();

 可以看到其注释中说明是JVM来创建线程的,而不同OS的JVM实现是具体与OS打交道的,那个native void start0()方法,没有实现体,是JVM实现的,就像是C#调用windows API一样,不过这里是调用JVM的"API".所以你必须知道创建线程和管理线程这事情是由JVM通信OS来实现的,是OS所特有的东西,和具体语言无关!当然也和平台无关,如.Net,Java,Python等等.

另外这个类直接从Runnable接口实现而来,所以这里需要澄清的是,它只是实现了run方法为一个空壳,里面没有具体功能,看一下它的构造函数:

可以看到具体干活的还是Runnable的实例,只是注入到Thread中而已,那么为什么Thread从Runnable实现,这就像一个适配器,一个默认的实现,我们可以直接重载Thread的run方法做一些事情(功能),而不必再用注入的方式使用它,而且从语义来讲,“功能的核”和“线程的壳“是在一起的,那么就会产生干不同活的Thread:

Java内建了很多具备不同功能的Thread类型(不仅有功能还是线程!)。
对于我们自己的功能线程,是使用继承覆盖还是接口注入的方式,完全取决于你。

 public class ThreadBasicDemo {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		Runnable runnableInterface = new Runnable() {

			@Override
			public void run() {
				System.out.println("do somethings");

			}

		};
		Thread newThread=new Thread(runnableInterface);
		newThread.start();

	}

}


使一个线程在操作系统中创建出来,只需要调用Thread的start方法即可,它知道如何在操作系统中创建线程,确切的说是在当前进程中创建,另外这里还提供了一个抽象层,那就是不管你是什么操作系统(windows,unix,linux),不管这些OS创建线程的方式有什么不同,它都能自动处理,调用方不需要知道!。另外Executor也可以执行一个Runnable所代表的任务,后面的文章中会有讲。

上面是创建线程的两种方式,都在java.lang包中,另外你可能注意到在run方法中只是返回一个void,也就是说不支持返回某些结果,但是很多时候你希望返回一些结果,幸好Java 5.0提供了Callable接口(在java.util.concurrent包中),它的作用和Runnable接口一样,但是它允许返回结果,在Java中它被声明成:

public interface java.util.concurrent.Callable {
  public java.lang.Object call() throws java.lang.Exception;
}


可以看到它与Runnable不同的地方就是可以返回结果(任何类型的),还可以抛出异常!
在使用方面,它不能与Thread联合直接使用,比如在构造函数中注入使用,因为如果等待一个结果的返回,就等于让主程序堵塞,所以它需要和Future一起配合使用,Future也是一个并发包中新类,代表了未来要”取“的结果:

  Callable<Object> callableInterface=new Callable<Object>() {

			@Override
			public Object call() throws Exception {
				System.out.println("do somethings");
				return null;
			}
		};


此接口还使用了泛型,也就是说我们可以为其设定任何返回类型。

ExecutorService threadpool = Executors.newFixedThreadPool(2);
Future<Object> p = threadpool.submit(callableInterface);


之后就可以通过Future的get方法取得结果,get会等待最终得到的结果,可以看出这是一个异步模型,也就是说”提交“给ExecutorService之后,就可以放任不管了,不会使主程序堵塞。对于ExecutorService,我会在后面的文章中讲到。

状态控制:
所有的线程都有生命周期,其中要经历的状态有(可以通过getState方法来查询):

NEW
Thread已被创建,但其start() method尚未被调用。所有线程都会从这个状
开始

RUNNABLE
线程正在运行或在操作系统调度它时就可运行。
BLOCKED
因为线程在等待取得锁定以便进入同步方法或程序块,所以线程并未运行。
WAITING
线程因为调用了 Object.wait()或Thread.join()而未运行。
TIMED_WAITING
线程因为调用了 Thread.sleep()或加上逾时值来调用 Object.wait()
Thread.join()而未运行。
TERMINATED
线程已运行完毕。它的 run()已正常结束或通过抛出异常而结束。

你可能很奇怪,Object.wait是干什么的,这是Java在所有类型基类Object中封装的方法,也就是说不管你是什么类型都有这个方法,不光只有这一个方法,还有notify和notifyAll方法,干什么用的哪?
wait就是把当前对象所在线程设置到等待状态,直到另外一个线程调用那个线程的Notify或者notifyAll来”通知“前面提到的那个线程结束等待状态继续运行,这对于一个等着另一个的场景实现很有帮助,另外后面的文章还会介绍一个semaphore类似于信号量的东西,也可以更加简单的做这样的事情。

异常处理
当一个线程出现了异常时,线程进入终止状态,但是如何处理这个异常哪?

 newThread.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
			
			@Override
			public void uncaughtException(Thread arg0, Throwable arg1) {
				//do somethings
				
			}
		});



线程的优先级
线程可以以不同的优先级运行。 指定优先级的线程通常会在已无具较高优先级的线程等
待时才会运行。在运作线程优先级时,你可以使用这里的一些程序代码:

// 将线程优先级设定为低于一般标准
t.setPriority(Thread.NORM_PRIORITY-1);
// 将线程的优先级设定为低于当前线程
t.setPriority(Thread.currentThread().getPriority() - 1);
// 不需等待I/O的线程应该要明确地让出CPU,以让其他具有相同优先
// 级的线程有机会运行
Thread t = new Thread(new Runnable() {
  public void run() {
    for(int i = 0; i < data.length; i++) { // 逐一处理一组数据
      process(data[i]); // 加以处理
      if ((i % 10) == 0) // 但在每处理10个后,就暂
        Thread.yield(); // 停以让其他线程运行
    }
  }
});


其中线程的yield方法起到一个复合作用,不像wait只是挂起当前线程,而是挂起当前线程,并通知其他线程开始运行。

Thread类的其他方法说明
stop():停止当前线程
sleep(..):让当前线程休眠一段时间
Thread.currentThread():得到当前线程
........
都比较简单,这里就不再描述和讲解了。下一篇将讲解线程的调度(全在java.util.concurrent包中,越来越进入到核心部分了)。


 

0
1
分享到:
评论
3 楼 leogao_emcom 2010-11-07  
有优先级倒置的情况,这就不符合线程原先制定的优先级了:
如果一个优先级高的线程等待一个优先级低的线程释放锁会导致优先级倒置,引起性能风险。
另外是不是不同的操作系统会造成差异,还没有核实。需要继续调研,
2 楼 liangguanhui 2010-11-03  
francis.xjl 写道
线程的优先级好像不一定管用

貌似是需要操作系统支持的说。
1 楼 francis.xjl 2010-11-03  
线程的优先级好像不一定管用

相关推荐

Global site tag (gtag.js) - Google Analytics