zoukankan      html  css  js  c++  java
  • 多线程入门(五)

    一、线程组

    1.Java中使用ThreadGroup来表示线程组,它可以对一批线程进行分类管理,Java允许程序直接对线程组进行控制。

    2.
    默认情况下,所有的线程都属于主线程组。
    •public final ThreadGroup getThreadGroup()

    我们也可以给线程设置分组(创建Thread类时用构造方法)
    •Thread(ThreadGroup group, Runnable target,String name) 

    3.统一操控(举例,直接拿ThreadGroup的方法设置里面的全部线程
    ThreadGroup tg = new ThreadGroup("这是一个新的组");
    //通过组名称设置后台线程,表示该组的线程都是后台线程
    tg.setDaemon(true);

    二、线程池


    程序启动一个新线程成本是比较高的,因为它涉及到要与操作系统进行交互。而使用线程池可以很好的提高性能,尤其是当程序中要创建大量生存期很短的线程时,更应该考虑使用线程池。一定初始大小数量线程们


    1.线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用。

    2.在JDK5之前,我们必须手动实现自己的线程池,从JDK5开始,Java内置支持线程池


    JDK5新增了一个Executors工厂类来产生线程池,有如下几个方法

    public static ExecutorService newCachedThreadPool()

    public static ExecutorService newFixedThreadPool(int nThreads)

    public static ExecutorService newSingleThreadExecutor()

    这些方法的返回值是ExecutorService对象,该对象表示一个线程池,可以执行Runnable对象或者Callable对象代表的线程。它提供了如下方法

    •Future<?> submit(Runnabletask)

    •<T> Future<T>submit(Callable<T> task)

    案例演示

    创建线程池对象

    创建Runnable实例

    提交Runnable实例

    关闭线程池

    /*
     * 线程池的好处:线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用。
     * 
     * 如何实现线程的代码呢?
     * 		A:创建一个线程池对象,控制要创建几个线程对象。
     * 			public static ExecutorService newFixedThreadPool(int nThreads)
     * 		B:这种线程池的线程可以执行:
     * 			可以执行Runnable对象或者Callable对象代表的线程
     * 			做一个类实现Runnable接口。
     * 		C:调用如下方法即可
     * 			Future<?> submit(Runnable task)
     *			<T> Future<T> submit(Callable<T> task)
     *		D:我就要结束线程池结束使用,可以吗?
     *			可以。
     */
    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();
    	}
    }



    三、多线程程序实现方案3(了解)

    实现Callable接口

    //Callable:是带泛型的接口。
    //这里指定的泛型其实是call()方法的返回值类型。没写泛型就默认是Object如下
    public class MyCallable implements Callable {
    
    	@Override
    	public Object call() throws Exception {
    		for (int x = 0; x < 100; x++) {
    			System.out.println(Thread.currentThread().getName() + ":" + x);
    		}
    		return null;
    	}
    
    }

    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方法分别是Runnable接口的和Thread子类对象的,那么到底执行谁的run方法?答案是执行Thread子类对象的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类来实现定义调度的功能

    Timer

    public Timer()

    public void schedule(TimerTask task, long delay)

    public void schedule(TimerTask task,long delay,long period)

    TimerTask

    public abstract void run()

    public boolean cancel()

    开发中

    Quartz是一个完全由java编写的开源调度框架。

    /*
     * 定时器:可以让我们在指定的时间做某件事情,还可以重复的做某件事情。
     * 依赖Timer和TimerTask这两个类:
     * Timer:定时
     * 		public Timer()
     * 		public void schedule(TimerTask task,long delay)
     * 		public void schedule(TimerTask task,long delay,long period)
     * 		public void cancel()
     * TimerTask:任务
     */
    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();
    	}
    
    }


    六、多线程常见的面试题

    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:线程的生命周期图

    新建 -- 就绪 -- 运行 -- 死亡

    新建 -- 就绪 -- 运行 -- 阻塞 -- 就绪 -- 运行 -- 死亡

    建议:画图解释。

  • 相关阅读:
    基于发布/订阅模型的应用程序的主循环设计
    C++使用继承时子对象的内存布局
    安装 CentOS 后的系统配置及软件安装备忘
    环形无锁队列
    并发编程基础
    线程池实现
    Git远程操作
    Unix权限管理
    jquery中,某些写法后来更新导致版本不支持的替代方法
    js相关
  • 原文地址:https://www.cnblogs.com/chz-blogs/p/9380997.html
Copyright © 2011-2022 走看看