javaAPI_多线程基础_多线程基础4
多线程基础4
1.线程组概述和使用
  (1).线程组概述 
      Java中使用ThreadGroup来表示线程组,它可以对一批线程进行分类管理,Java允许程序直接对线程组进行控制。
  (2).代码测试
    //线程类代码
	public class MyRunnable implements Runnable {
	@Override
	public void run() {
		for (int x = 0; x < 100; x++) {
			System.out.println(Thread.currentThread().getName() + ":" + x);
		}
	}
    }
	//测试类代码
	public class ThreadGroupDemo {
	public static void main(String[] args) {
		// method1();
		// 我们如何修改线程所在的组呢?
		// 创建一个线程组
		// 创建其他线程的时候,把其他线程的组指定为我们自己新建线程组
		method2();
		// t1.start();
		// t2.start();
	}
	/*
	 * 重新创建线程组
	 *
	 */
	private static void method2() {
		// ThreadGroup(String name)
		ThreadGroup tg = new ThreadGroup("这是一个新的组");
		MyRunnable my = new MyRunnable();
		// Thread(ThreadGroup group, Runnable target, String name):把线程指定为某一个线程组的
		Thread t1 = new Thread(tg, my, "林青霞");
		Thread t2 = new Thread(tg, my, "刘意");
		
		System.out.println(t1.getThreadGroup().getName());
		System.out.println(t2.getThreadGroup().getName());
		
		//通过组名称设置后台线程,表示该组的线程都是后台线程
		tg.setDaemon(true);
	}
	/*
	 * 默认情况测试
	 * 获取当前的线程组以及使用线程组中的方法
	 */
	private static void method1() {
		MyRunnable my = new MyRunnable();
		Thread t1 = new Thread(my, "林青霞");
		Thread t2 = new Thread(my, "刘意");
		// 我不知道他们属于那个线程组,我想知道,怎么办
		// 线程类里面的方法:public final ThreadGroup getThreadGroup()
		ThreadGroup tg1 = t1.getThreadGroup();
		ThreadGroup tg2 = t2.getThreadGroup();
		// 线程组里面的方法:public final String getName()
		String name1 = tg1.getName();
		String name2 = tg2.getName();
		System.out.println(name1);
		System.out.println(name2);
		// 通过结果我们知道了:线程默认情况下属于main线程组
		// 通过下面的测试,你应该能够看到,默任情况下,所有的线程都属于同一个组
		System.out.println(Thread.currentThread().getThreadGroup().getName());
	}
    }
	
2.线程池概述以及使用
  (1).概述
      程序启动一个新线程成本是比较高的,因为它涉及到要与操作系统进行交互。而使用线程池可以很好的提高性能,尤其是
	  当程序中要创建大量生存期很短的线程时,更应该考虑使用线程池。
	  
  (2).线程池的特点
      线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用
  (3).JDK5新增了一个Executors工厂类来产生线程池。具体方法如下:
      public static ExecutorService newCachedThreadPool()
      public static ExecutorService newFixedThreadPool(int nThreads)
      public static ExecutorService newSingleThreadExecutor()
	  
	  这些方法的返回值是ExecutorService对象,该对象表示一个线程池,可以执行Runnable对象或者Callable对象代表的线程。
	  它提供了如下方法:
       Future<?> submit(Runnable task)
       <T> Future<T> submit(Callable<T> task)
	   
  (4).线程池使用测试
  
      A:如何实现线程的代码呢?
  		A:创建一个线程池对象,控制要创建几个线程对象。
  			public static ExecutorService newFixedThreadPool(int nThreads)
  		B:这种线程池的线程可以执行:
  			可以执行Runnable对象或者Callable对象代表的线程
  			做一个类实现Runnable接口。
  		C:调用如下方法即可
  			Future<?> submit(Runnable task)
 			<T> Future<T> submit(Callable<T> task)
 		D:我就要结束,可以吗?
	    	可以。
			
      B:具体使用代码:
	  //线程类代码 
	  public class MyRunnable implements Runnable {
	     @Override
	     public void run() {
		    for (int x = 0; x < 100; x++) {
			System.out.println(Thread.currentThread().getName() + ":" + x);
		  }
	    }
      }	  
	  //测试类代码
	  public static void main(String[] args) {
		// 创建一个线程池对象,控制要创建几个线程对象。
		// public static ExecutorService newFixedThreadPool(int nThreads)
		ExecutorService pool = Executors.newFixedThreadPool(2);
		// 可以执行Runnable对象或者Callable对象代表的线程
		pool.submit(new MyRunnable());
		pool.submit(new MyRunnable());
		//结束线程池
		pool.shutdown();
	}
3.匿名内部类实现多线程
  
  (1).实际开发中最简单的方式开启另一个线程,那么就是使用匿名内部类的方式实现。
      new Thread(){代码…}.start();
      New Thread(new Runnable(){代码…}).start();
	  
	  
  (2).代码实现
/*
 * 匿名内部类的格式:
 * 		new 类名或者接口名() {
 * 			重写方法;
 * 		};
 * 		本质:是该类或者接口的子类对象。
 */
public class ThreadDemo {
	public static void main(String[] args) {
		// 继承Thread类来实现多线程
		new Thread() {
			public void run() {
				for (int x = 0; x < 100; x++) {
					System.out.println(Thread.currentThread().getName() + ":"
							+ x);
				}
			}
		}.start();
		// 实现Runnable接口来实现多线程
		new Thread(new Runnable() {
			@Override
			public void run() {
				for (int x = 0; x < 100; x++) {
					System.out.println(Thread.currentThread().getName() + ":"
							+ x);
				}
			}
		}) {
		}.start();
		// 更有难度的
		new Thread(new Runnable() {
			@Override
			public void run() {
				for (int x = 0; x < 100; x++) {
					System.out.println("hello" + ":" + x);
				}
			}
		}) {
			public void run() {
				for (int x = 0; x < 100; x++) {
					System.out.println("world" + ":" + x);
				}
			}
		}.start();
	}
    }
4.定时器
  
  (1).概述
      定时器是一个应用十分广泛的线程工具,可用于调度多个定时任务以后台线程的方式执行。在Java中,可以通过Timer和
	  TimerTask类来实现定义调度的功能
  (2).相关方法
     Timer类:定时
  		public Timer()
  		public void schedule(TimerTask task,long delay):延时指定时间以后执行任务
  		public void schedule(TimerTask task,long delay,long period):指定时间以后连续执行
  		public void cancel():终止任务
		
     TimerTask类:任务(需要重写里面的方法)
	 
  (3).定时器基本使用测试[指定延时以后执行任务]
   public class TimerDemo {
	public static void main(String[] args) {
		// 创建定时器对象
		Timer t = new Timer();
		// 3秒后执行爆炸任务
		// t.schedule(new MyTask(), 3000);
		//结束任务
		t.schedule(new MyTask(t), 3000);
	}
   }
   // 做一个任务
   class MyTask extends TimerTask {
	private Timer t;
	
	public MyTask(){}
	
	public MyTask(Timer t){
		this.t = t;
	}
	
	@Override
	public void run() {
		System.out.println("beng,爆炸了");
		t.cancel();
	}
  }
    
  (4).多次执行代码[3秒后执行任务第一次,如果不成功,每隔2秒再继续]
   public class TimerDemo2 {
	public static void main(String[] args) {
		// 创建定时器对象
		Timer t = new Timer();
		// 3秒后执行爆炸任务第一次,如果不成功,每隔2秒再继续炸
		t.schedule(new MyTask2(), 3000, 2000);
	}
   }
   // 做一个任务
  class MyTask2 extends TimerTask {
	@Override
	public void run() {
		System.out.println("beng,爆炸了");
	}
   }
   
   
   (5).定时器使用案例:定时删除文件或者是文件夹
/*
 * 需求:在指定的时间删除我们的指定目录(你可以指定c盘,但是我不建议,我使用项目路径下的demo)
 */
class DeleteFolder extends TimerTask {
	@Override
	public void run() {
		File srcFolder = new File("demo");
		deleteFolder(srcFolder);
	}
	// 递归删除目录
	public void deleteFolder(File srcFolder) {
		File[] fileArray = srcFolder.listFiles();
		if (fileArray != null) {
			for (File file : fileArray) {
				if (file.isDirectory()) {
					deleteFolder(file);
				} else {
					System.out.println(file.getName() + ":" + file.delete());
				}
			}
			System.out.println(srcFolder.getName() + ":" + srcFolder.delete());
		}
	}
}
public class TimerTest {
	public static void main(String[] args) throws ParseException {
		Timer t = new Timer();
		String s = "2014-11-27 15:45:00";
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		Date d = sdf.parse(s);
		t.schedule(new DeleteFolder(), d);
	}
}
5.多线程相关面试题
(1):多线程有几种实现方案,分别是哪几种?
	两种。
	
	继承Thread类
	实现Runnable接口
	
	扩展一种:实现Callable接口。这个得和线程池结合。
(2):同步有几种方式,分别是什么?
	两种。
	
	同步代码块
	同步方法
(3):启动一个线程是run()还是start()?它们的区别?
	start();
	
	run():封装了被线程执行的代码,直接调用仅仅是普通方法的调用
	start():启动线程,并由JVM自动调用run()方法
(4):sleep()和wait()方法的区别
	sleep():必须指时间;不释放锁。
	wait():可以不指定时间,也可以指定时间;释放锁。
(5):为什么wait(),notify(),notifyAll()等方法都定义在Object类中
	因为这些方法的调用是依赖于锁对象的,而同步代码块的锁对象是任意锁。
	而Object代码任意的对象,所以,定义在这里面。
(6):线程的生命周期图
	新建 -- 就绪 -- 运行 -- 死亡
	新建 -- 就绪 -- 运行 -- 阻塞 -- 就绪 -- 运行 -- 死亡
	建议:画图解释。
                    
                
                
            
        
浙公网安备 33010602011771号