java线程学习笔记(一)

原创 2013年12月08日 14:13:39

        在JAVA中如果一个程序开始运行,那么至少有2个线程,一个是我们熟悉的main线程,而另外一个则是JVM的垃圾回收器,实际上每启动一个程序都会建立一个JVM,即一个进程,而如果我们想在主线程之外建立一个新的线程,而不影响主线程的运行,这时我们有三种实现方式,以下是我的一些学习心得。

    (一)java中线程的实现方式

      在java实现一个线程的方式有三种,一种是继承Thread类,另外一种是实现Runnable接口,还有就是使用Callable和Future创建线程,其中,前两种方式的原理都是重新下run方法,一般来说实现Runnable接口比继承Thread类更加具有优势,主要原因有以下二点;

      1.实现Runnable接口可以避免java单继承的限制,从而可以便于类的扩展;

      2.在需要实现若干功能逻辑相同的线程时,采用实现Runnable的方式,可以有效的提高代码的重用性,避免代码的冗余,便于资源的共享。

      以下是具体的代码的例子,实现Runnable接口的例子:

public class FristThread implements Runnable{


int countNum = 5 ;

    public void run() {
       
    for(int i = 0 ; i < 5 ; i++){
    
    if(countNum > 0 ){
    
    System.out.println(Thread.currentThread().getName()+"-----> countNum  is --->" + countNum--);
    }
    
    }
    }
}


    主函数的测试代码为:

 public static void main(String[] args){
  
  FristThread thread1 = new FristThread();
  Thread h1=new Thread(thread1,"A");
  Thread h2=new Thread(thread1,"B");
  Thread h3=new Thread(thread1,"C");
  h1.start();
  h2.start();
  h3.start();

}


  

可以看到执行的结果为:

B-----> countNum  is --->5
B-----> countNum  is --->4
B-----> countNum  is --->3
A-----> countNum  is --->2
C-----> countNum  is --->1

而采用继承Thread的方式的实现代码为:

public class FristThread extends Thread {
int countNum = 5;
@Override
public void run() {
super.run();
for (int i = 0; i < 5; i++) {
  if(countNum > 0 ){
    
    System.out.println(Thread.currentThread().getName()+"-----> countNum  is --->" + countNum--);
    }
}
}
}


主函数测试代码:

public static void main(String[] args){

FristThread thread1 = new FristThread();
FristThread thread2 = new FristThread();
FristThread thread3 = new FristThread();
thread1.start();
thread2.start();
thread3.start();
}


可以看到运行结果为:

Thread-1-----> countNum  is --->5
Thread-1-----> countNum  is --->4
Thread-1-----> countNum  is --->3
Thread-1-----> countNum  is --->2
Thread-1-----> countNum  is --->1
Thread-0-----> countNum  is --->5
Thread-0-----> countNum  is --->4
Thread-0-----> countNum  is --->3
Thread-0-----> countNum  is --->2
Thread-0-----> countNum  is --->1
Thread-2-----> countNum  is --->5
Thread-2-----> countNum  is --->4
Thread-2-----> countNum  is --->3
Thread-2-----> countNum  is --->2
Thread-2-----> countNum  is --->1

   从上面的运行结果我们可以看到,通过实现Runnable接口的方式实现线程,可以实现公共的资源的共享。

   在这里还需要注意的是启动线程只能通过调用线程的start的方法,而调用run方法,只是相当于调用该类的一个方法。

 最后的一种实现方式是使用Callable和Future创建线程

  从java5开始,JDK提供了callable接口,java API提供的介绍是这样的:Callable 接口类似于 Runnable,两者都是为那些其实例可能被另一个线程执行的类设计的。但是Runnable 不会返回结果,并且无法抛出经过检查的异常,callable接口提供了一个call方法,这个方法相当于Runnable的run方法,Future接口表示异步计算的结果,它提供了检查计算是否完成的方法,以及等待计算的完成,并获取计算的结果,我们在使用它时常常使用的是,它的实现类FutureTask,FutrueTask类提供了对Future 的基本实现。仅在计算完成时才能获取结果;如果计算尚未完成,则阻塞 get 方法。一旦计算完成,就不能再重新开始或取消计算。可以用FutureTask来包装callable接口或者Runnable接口,因为FutureTask接口实现了Runnable,所以我们可以把它提供给Executor 执行,同样的道理,因为FutureTask实现了Runnable接口使用,可以在生成线程时把他当着Thread类构造函数的中的线程参数进行传入。

   以下是一个简单的应用实例:

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;


public class CallableTest implements Callable<Integer>{

	public static void main(String[] args) {
		
		/** 
		 * 生成一个callable实现类的对象,这个实现类包含了一个call方法,这个call方法
		 * 相当于Runnable的run方法,是线程的具体任务。
		 */
		CallableTest callableTest=new CallableTest();
		/**
		 * 使用FutureTask对象来包装callable实现对象,该FutureTask对象
		 * 实际上就是封装了callable类的call方法的返回结果
		 */
		FutureTask<Integer> futureTask=new FutureTask<Integer>(callableTest);
		/**
		 * 使用futureTask创建线程
		 */
		new Thread(futureTask, "futureTask").start();
		
		try {
			
			System.out.println("子线程执行完成并且返回 : "+futureTask.get());
			
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (ExecutionException e) {
			e.printStackTrace();
		}
	}
	@Override
	public Integer call() throws Exception {
		
		int i = 0;
		for( ;i < 5 ; i++ ){
			System.out.println("子线程循环-----i = " + i);
		}
		return i;
	}
}
执行结果为:

子线程循环-----i = 0
子线程循环-----i = 1
子线程循环-----i = 2
子线程循环-----i = 3
子线程循环-----i = 4
子线程执行完成并且返回 : 5

以上是三种线程的实现方式,详细的介绍可以参考JDK API进行查询。



学完分享:李刚《疯狂JAVA讲义》学习笔记思维导图版

李刚老师的《疯狂JAVA讲义》厚达800多页,如果不做任何笔记并将知识体系化,很难将里面的知识内化成自己的东西。我在三个月的学习过程中,不但认真完成里面的实验,而且细心梳理了知识结构,并通过思维导图软...
  • midong2000
  • midong2000
  • 2013年12月28日 15:58
  • 3012

数据库笔记(自己学习过程中整理)

编程语言是实现对内存的操作比较方便,对硬盘数据的操作数据库比较方便   一、数据库如何存储数据的 字段,记录,表,约束(主键,外键,唯一键,非空,check,default)   二、如何操作数据 i...
  • Caster_Saber
  • Caster_Saber
  • 2015年05月17日 16:20
  • 1660

《Java JDK8学习笔记》读书笔记(4)

第4章 认识对象 学习目标  区分基本类型与对象类型  了解对象与引用的关系  从打包器认识对象  以对象观点看待数组  认识字符串的特性...
  • mouyong
  • mouyong
  • 2016年04月18日 20:10
  • 4396

Java分布式应用学习笔记03JVM对线程的资源同步和交互机制

  • 2011年09月28日 17:22
  • 277KB
  • 下载

java线程学习笔记

  • 2012年07月30日 17:51
  • 15KB
  • 下载

03-java学习笔记【进程与线程】

原文链接http://blog.csdn.net/yaosiming2011/article/details/44280797 1.定义 a.进程是具有一定独立功能的程序关于某个数据集合上的一...
  • sinat_28381507
  • sinat_28381507
  • 2016年11月15日 22:45
  • 76

黑马程序员——java线程学习笔记

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
  • zhuzhuflyxia
  • zhuzhuflyxia
  • 2015年05月02日 22:00
  • 201

深入理解java虚拟机学习笔记-5.内存与线程

内存与线程1 内存1.1 内存一致性由于计算机的存储设备与处理器的运算速度之间有着几个数量级的差距,所以现代计算机系统都不得不加入一层读写速度尽可能接近处理器运算速度的高速缓存(Cache)来作为内存...
  • cnwuhao
  • cnwuhao
  • 2017年08月06日 22:26
  • 175

【Java学习笔记】14:再谈线程的启动和暂时停止

线程,即正在执行程序的主体。 在单线程程序里,在某一时间点进行的处理只有一个。也就是说如果在任一时间提出问题“正在执行程序的哪里?”,可以指出程序中的某一点“就是这里”。 实际上严格地说,有些必须的线...
  • SHU15121856
  • SHU15121856
  • 2017年04月26日 11:23
  • 329

Java线程和线程池学习笔记

Java线程的使用方式最基础的来说只有两种:实现Runnable和Callable接口,继承Thread类实际也是间接实现了Runnable接口。两者的区别的是Runnable没有返回值,而Calla...
  • wuqinghai2012
  • wuqinghai2012
  • 2016年05月08日 20:08
  • 255
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:java线程学习笔记(一)
举报原因:
原因补充:

(最多只允许输入30个字)