zoukankan      html  css  js  c++  java
  • java线程一之创建线程、线程池以及多线程运行时间统计

    线程和进程的基本概念

    进程和线程是动态的概念。

            进程是 “执行中的程序“,是一个动词,而程序是一个名词,进程运行中程序的”代码“,而且还有自己的计数器,寄存器,它会向系统申请系统资源。

            线程是进程中的一个控制流。一个程序可能可能包含多个任务并发运行,而线程就是指一个任务重头到尾的执行流。

            说的在简单点,线程是执行中的任务,一个程序包含多个任务。

     

    多线程

           单处理器中,为提高处理器的使用率(最终目标),使得程序在进行IO输入出等不需要处理器时,也能够让处理器在运转,引进多线程处理机制。多线程可以使得程序运行的更快,执行效率更高,交互性更强,这是不言而喻的!

     

    创建任务和线程

            一个任务是一个对象,所以为创建一个任务,必须定义一个类,定义一个任务类,为了说明这是一个任务类,它需要实现Runnable接口,这个接口只包含一个run方法。

    当我们定义好任务类taskClass之后,就可以用它的构造方法创建一个任务啦:TaskClass  task = new TaskClass(.....);

            我们创建的任务只能在线程中运行,Thread类中包含了创建线程以及控制线程的众多方法。使用下面的语句创建任务线程:Thread  thread  = new Thread(task);

            然后调用start()方法告诉java虚拟机该线程准备运行thread.start();之后java虚拟机通过调用任务的run()方法执行任务。

     

    事例代码:

    public class TaskThreadDemo{
    	public static void main(String[] args)
    	{
    		//创建任务   并且需要为任务 创建 任务类,使用该类的构造方法创建任务
    		PrintChar printA = new PrintChar('a',100);
    		PrintChar printB = new PrintChar('b',100);
    		PrintNum print100 = new PrintNum(100);
    		
    		//为任务创建线程
    		Thread thread1 = new Thread(printA);
    		Thread thread2 = new Thread(printB);
    		Thread thread3= new Thread(print100);
    		
    		//告诉虚拟机器线程开始运行
    		thread1.start();
    		thread2.start();
    		thread3.start();
    	}
    }
    
    class PrintChar implements Runnable
    {
    	private char  charToPrint;
    	private int items;
    	
    	public PrintChar(char c,int t)
    	{
    		charToPrint = c;
    		items = t;
    	}
    
    	@Override
    	public void run() {
    		// TODO Auto-generated method stub
    		for(int i=0;i<items;i++)
    		{
    			System.out.print(charToPrint);
    		}
    	}
    }
    
    class PrintNum implements Runnable
    {
    	private int lastNumb;
    	public PrintNum(int n)
    	{
    		lastNumb = n;
    	}
    	@Override
    	public void run() {
    		// TODO Auto-generated method stub
    		for(int i= 1;i<100;i++)
    		{
    			System.out.print(" "+lastNumb); 
    		}
    	}

    }

     

    6fdaf34c50434bf5bab9d149c7fccc4c

     

    一个好玩的闪烁文本框,直接用线程,不用main方法

    import javax.swing.JApplet;
    import javax.swing.JLabel;
    public class FlashingText extends JApplet implements Runnable {
    	private static final long serialVersionUID = 1L;
    	private JLabel jlbText = new JLabel("Welcome",JLabel.CENTER);
    	
    	public FlashingText()
    	{
    		add(jlbText);
    		new Thread(this).start();
    	}
    	
    	public void run()
    	{
    		try {
    			while(true)
    			{
    				if(jlbText.getText()==null)
    					jlbText.setText("Welcome");
    				else 
    					jlbText.setText(null);
    				Thread.sleep(200);
    			}
    		} catch (Exception e) {
    			// TODO: handle exception
    		}
    	}
    }

     

    ed611650e460458198ca7b12d26f387fa28aa6938f9645578293e2a7e193c531

     

    Thread类

            Thread类实现了Runnable接口,它包含为任务而创建线程的构造方法,以及控制方法,下图就是Thread类常见的控制线程的方法:

    iirj8`ilw}dr

              因为Thread类实现了Runnable接口,所以可以定义一个Thread的扩展类,里面实现run方法,这样也可以创建一个线程类,但并不是很推荐这种方法,因为它将创建任务和运行任务的机制混在了一起,将任务从线程中分离出来比较好,即尽量使用Runnable接口创建线程,这样得到的线程更加灵活,避免了java单继承带来的局限性

     

    线程池

               线程池是管理并发执行任个数的理想方法,java提供Executor接口来执行线程池中的任务,提供ExecutorService接口来管理和控制任务。为了创建Executor接口实例,我们可以用Executors类,Executors类提供了创建Executor接口对象的静态方法,下图描述了上面的上面所说的关系。

    clipboard

     

           线程池中的shutdown()方法一般都是放在main方法的后面部分,当所以的线程都添加到线程池中,即便有线程没有执行完毕,也可能会关闭线程池,未执行完的线程继续执行,所以main方法可能比子线程先结束。

    利用isTerminated()进行线程池中所有线程运行时间的统计

           倘若希望主线程在子线程全部做完之后在执行,可以考虑让所以的子线程用jion方法,但这可能导致所有子线程变成串行,不是很好的办法,当然我们也可以多线程的辅助类CountDownLatch,这是一个与计时器有点类似功能的类。这次在看书学习的时候,发现了一个更好的办法,就是在shutdown()方法后加上一句while(!executor.isTerminated()){},这是一个不错的方法(不过我把shoudown()方法放在该while语句后面,就会陷入死循环,应该是要先关闭线程池,在判断线程池中的线程是否全部终止,因为也有可能在while语句后面在添加新的子线程)。

           isTerminated()方法:如果线程池中所以线程都已完成并终止,则返回true.

           可以使用CountDownLatch 和上面的方法对程序运行计时统计,不过我记得CountDownLatch类是需要指定线程的个数。

    事例代码

    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    public class ExecutorDemo {
    	public static void main(String[] args){
    		long start = System.currentTimeMillis();
    		System.out.println("当前时间"+"  "+start);
    		ExecutorService executor = Executors.newFixedThreadPool(4);
    		
    		executor.execute(new PrintChar('a',100));
    		executor.execute(new PrintChar('b',100));
    		executor.execute(new PrintChar('c',100));
    	    executor.execute(new PrintNum(100));
    	    
    	    executor.shutdown();
    		while(!executor.isTerminated()){
    			//System.out.print("-");
    		};
    		
    		long end = System.currentTimeMillis();
    		System.out.println("
    当前时间"+"  "+end);
    		System.out.println("
    用时"+"  "+(end-start)+"毫秒");
    	}
    }
     
    运行截图
    3015774f9c88408286aa07f7c77a10db 截图1      572ff3bc5ea7495d9f207f5971a731a9截图2

             不过不知道运行太快的原因,还是啥别的原因, 会出现截图2的情况,网上很少关于isTerminated()方法的介绍,如有大神知道原因,还请告知小弟。

     

             这篇博客是自己在学习《java语言程序设计进阶篇》时所在笔记,代码出自书上,最后那个记时的加了计时部分。大三开学在即,希望现在来学java还来得及。

    本文出自于博客园兰幽,转载请说明出处。

  • 相关阅读:
    HTML5响应式导航
    草原图片大全
    草原psd素材
    仿堆糖图片自滚动瀑布流效果
    夏日户外风景PSD素材
    国画经典之梅花PSD素材
    更改VS的运行主窗体
    在VS中如何更换项目名称
    如何使用Visual Studio 2008(VS2008)编译C语言
    #region 私有字段
  • 原文地址:https://www.cnblogs.com/LZYY/p/3959557.html
Copyright © 2011-2022 走看看