Java中使用ThreadGroup来表示线程组,它可以对一批线程进行分类管理,Java允许程序直接对线程组进行控制。 ①public final ThreadGroup getThreadGroup() 默认情况下,所有的线程都属于主线程组。 ②public final String getName() 返回此线程组的名称。 修改线程所在的组 创建一个线程组,创建其他线程的时候,把其他线程的组指定为我们自己新建线程组。 Thread(ThreadGroup group, Runnable target, String name)
// 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); //可通过ThreadGroup方法统一操作整个线程组线程程序启动一个新线程成本是比较高的,因为它涉及到要与操作系统进行交互。而使用线程池可以很好的提高性能,尤其是当程序中要创建大量生存期很短的线程时,更应该考虑使用线程池。 线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用。 在JDK5之前,我们必须手动实现自己的线程池,从JDK5开始,Java内置支持线程池。
JDK5新增了一个Executors工厂类来产生线程池,有如下几个方法: ①public static ExecutorService newCachedThreadPool() 创建一个具有缓存功能的线程池。 ②public static ExecutorService newFixedThreadPool(int nThreads) 创建一个可重用的,具有固定线程数的线程池。 ③public static ExecutorService newSingleThreadExecutor() 创建一个只有单线程的线程池,相当于上个方法的参数是1。
这些方法的返回值是ExecutorService对象,该对象表示一个线程池,可以执行Runnable对象或者Callable对象代表的线程。它提供了如下方法: Future<?> submit(Runnable task) Future submit(Callable task) Future表示异步计算的结果。
①创建一个线程池对象,控制要创建几个线程对象。 -public static ExecutorService newFixedThreadPool(int nThreads) ②这种线程池的线程可以执行: -可以执行Runnable对象或者Callable对象代表的线程 -做一个类实现Runnable接口。 ③调用如下方法即可 -Future<?> submit(Runnable task) - Future submit(Callable task) ④结束线程池
public class ExecutorsDemo { 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(); } }实现Callable接口特点 好处: 可以有返回值,可以抛出异常。 弊端: 代码比较复杂,所以一般不用。
异步求和代码示例
public class CallableDemo { public static void main(String[] args) throws InterruptedException, ExecutionException { // 创建线程池对象 ExecutorService pool = Executors.newFixedThreadPool(2); // 可以执行Runnable对象或者Callable对象代表的线程 Future<Integer> f1 = pool.submit(new MyCallable(100)); Future<Integer> f2 = pool.submit(new MyCallable(200)); // V get() Integer i1 = f1.get(); Integer i2 = f2.get(); System.out.println(i1); System.out.println(i2); // 结束 pool.shutdown(); } }匿名内部类的格式:
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(); // 更有难度的,此时会走子类对象中的run()方法 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(); } }定时器是一个应用十分广泛的线程工具,可用于调度多个定时任务以后台线程的方式执行。在Java中,可以通过Timer和TimerTask类来实现定义调度的功能。
public Timer() 创建一个新的定时器。 public void schedule(TimerTask task, long delay) 安排在指定的时间执行指定的任务。 public void schedule(TimerTask task,long delay,long period) 安排指定的任务从指定的延迟后开始进行重复的固定延迟执行。
public abstract void run() 此计时器任务要执行的操作。 public boolean cancel() 取消此计时器的任务。
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("boom,爆炸了"); t.cancel(); } }在开发中使用Quartz,Quartz是一个完全由java编写的开源调度框架。 思考题
思考1: 多线程有几种实现方案,分别是哪几种?答:
两种。 继承Thread类 实现Runnable接口 扩展一种:实现Callable接口。这个得和线程池结合。答:
两种。 同步代码块 同步方法答:
start(); run():封装了被线程执行的代码,直接调用仅仅是普通方法的调用。 start():启动线程,并由JVM自动调用run()方法。答:
sleep():必须指定时间;不释放锁。 wait():可以不指定时间,也可以指定时间;释放锁。答:
因为这些方法的调用是依赖于锁对象的,而同步代码块的锁对象是任意锁。 而Object代表任意的对象,所以,定义在这里面。线程的生命周期图