zoukankan      html  css  js  c++  java
  • Thinking In Java第二十一章学习笔记----并发

      初学者的疑惑:线程是一个任务?错。

      在Java中,Thread类自身不执行任何操作,它只是驱动赋予它的任务,但是线程研究中总是使用"线程执行这项或那项任务"这样的言语,因此给人强烈的错觉是线程就是一个任务,其实不然。从概念上说,我们希望创建独立于其他任务的任务,因此我们应该可以定义任务,然后说"开始执行",并且不用操心其细节。但是在物理上,创建线程可能会代价高昂,因此你必须保存并管理他们。从实现的角度看,将任务从线程中分离出来是很有意义的。另外,程序员也是要面子的,我们已经对Thread类没有任何控制权,如果连任务的具体定义的资格都没有,那线程也就没有存在的必要了,因为那是自取其辱。另外,Java的线程机制来自于C的低级的P线程方式。这是一种你必须深入研究,并且需要完全理解其所有事物的所有细节的方式。

      定义任务:

      线程需要驱动任务(其实是驱动实现了Runnable接口的类的对象),因此需要一种描述任务的方式,而Runnable接口可以提供。要想定义任务,只需实现Runnable接口并实现run()方法,使得该任务可以执行你的命令。

      因此,Run方法才是真正的任务。

      当从Runnable中导出一个类时,它必须具有run()方法,但是这个方法并无特殊之处——它不会产生任何内在的线程能力,要实现线程行为,必须显示的将一个任务附着到线程上。

      线程驱动方式:

      1)直接通过Thread来驱动

      Thread构造器只需要一个Runnable对象。调用Thread对象的start()方法为该线程进行必要的初始化操作,然后才是调用Runnable()的run()方法,以便在新线程中启动该任务。

      下面的示例中需要注意的是,虽然start()方法迅速返回了,但是后面的输出语句先执行,是因为除了 t 线程之外,还有一个main()主线程,此时main()主线程拥有系统时间片,所以先执行后面的语句,然后 t 线程获取到系统时间片,继续调用run()方法。

    class LiftOff implements Runnable {
    	public void run() {
    		System.out.println("定义任务");
    	}
    }
    
    public class BasicThreads {
    	public static void main(String[] args) {
    		Thread t = new Thread(new LiftOff());
    		t.start();
    		System.out.println("先于run()方法输出");
    	}
    }
    

      当然,你可以添加更多的线程去驱动更多的任务,如下:

    class LiftOff1 implements Runnable {
        protected int countDown = 10;
        private static int taskCount = 0 ;
        private final int id  = taskCount++;
    public String status() { return "#" + id + "(" + (countDown > 0 ? countDown : "LiftOff") + ")"; }
    public void run() { while(countDown-- >0) { System.out.println(status()); Thread.yield(); } } } public class MoreBasicThreadS {
    public static void main(String[] args) { for (int i = 0; i <5 ; i++) new Thread(new LiftOff1()).start(); System.out.println("Waiting for LiftOff"); }
    }

      Thread.yield():

      一般用在当前线程主要任务已经完成时,将自己从运行状态转化为就绪状态,希望可以切换执行其他线程,但是需要注意,该线程下次仍然有可能被分配到系统时间片。所以这仅是一个好的初衷,是否实现,随缘。

      此外,较早的JDK不会频繁对时间切片,某个线程可能会先循环到尽头,再开始下个线程的执行。较晚的JDK看起来有更好的时间切片行为,让各个线程执行的更加"均匀"。

      2)使用Executor

      Java SE5的java.util.concurrent包中的执行器Executor可以帮助我们管理Thread对象,大大简化并发编程。Executor在客户端和任务执行之间提供了一个间接层,与客户端直接执行任务不同,这个中介对象将执行任务。

      Executor、ExecutorService、Executors:

      

      区别:

    • ExecutorService 接口继承了 Executor 接口,是 Executor 的子接口。
    • Executor 接口定义了 execute()方法用来接收一个Runnable接口的对象,而 ExecutorService 接口中的 submit()方法可以接受Runnable和Callable接口的对象。
    • Executor 中的 execute()方法不返回任何结果,而 ExecutorService 中的submit()方法可以通过一个 Future 对象返回运算结果。
    • Executor 和 ExecutorService 接口都允许客户端提交一个任务,但ExecutorService 还提供用来控制线程池的方法。比如:调用 shutDown()方法终止线程池。
    • Executors 是一个类,提供工厂方法用来创建不同类型的线程池。比如:newSingleThreadExecutor()创建一个只有一个线程的线程池,newFixedThreadPool(int numOfThreads)来创建固定线程数的线程池,newCachedThreadPool()可以根据需要创建新的线程,但如果已有线程是空闲的会重用已有线程。

     

  • 相关阅读:
    SQL Server Audit监控触发器状态
    SQL Server 数据变更时间戳(timestamp)在复制中的运用
    SQL Server 更改跟踪(Chang Tracking)监控表数据
    SQL Server 变更数据捕获(CDC)监控表数据
    SQL Server 事件通知(Event notifications)
    SQL Server 堆表行存储大小(Record Size)
    SQL Server DDL触发器运用
    SQL Server 默认跟踪(Default Trace)
    SQL Server 创建数据库邮件
    SQL Server 跨网段(跨机房)FTP复制
  • 原文地址:https://www.cnblogs.com/promiseslc/p/9247960.html
Copyright © 2011-2022 走看看