• java 多线程二


     看下面的一段程序,通过并行运行2个线程。

    import java.util.Date;
    
    
    public class GreetingRunnable implements Runnable {
        int pauseTime;
        String name;
        public GreetingRunnable(int x, String n) {
            pauseTime = x;
            name = n;
        }
        public void run() {
          for(int i=1;i<=10;i++)
          {
              Date now=new Date();
              System.out.println(now+" "+name);
    Thread.sleep(pauseTime); } }
    static public void main(String args[]) { Thread t1 = new Thread (new GreetingRunnable(1000, "hello world ")); t1.start(); Thread t2 = new Thread (new GreetingRunnable(1000, "goodbye world")); t2.start(); } }

      输出时, 因为两个线程并行运行,所以两个信息集是交错的。但是,仔细查看,会发现两个线程不是完全交错的,有时,第二个线程会跳到第一个线程的前面,这表明了线程的一个重要特点。线程调度器没有保证线程被执行的顺序。每个线程都运行称为时间片的一小段时间。然后调度器激活另一个线程。但是,运行时间总是会有微小变化。所以,线程得到控制权的顺序是有些随机的。

       如果main方法中进行下面方法的调用而不是启动线程。会输出什么结果?

     t1.run(); 

    t2.run();

    输出:对run的第一个调用输出10条hello,第二次调用输出10条goodbye。

      创建大量生命短暂线程的程序是低效的。线程由操作系统管理,被创建的线程有空间和运行时间成本。这些成本可由线程池来降低。

    线程池创建许多线程并让他们保持活动状态。在将Runnable对象加到线程池后,下一个空闲线程就执行他的run方法

      下面语句将2个对象提交到线程池。

    Runnable r1=new GreetingRunnable(1000,"hello world");
    
            Runnable r2=new GreetingRunnable(1000,"goodbye world");
    
            ExecutorService pool=Executors.newFixedThreadPool(MAX_THREADS);
    
            pool.execute(r1);
    
            pool.execute(r2);

     如果许多可运行对象被提交执行,那么该线程池可能没有足够的线程可用。在这种情况下,有些可运行对象就被放入 队列,直到有线程空闲为止。结果,创建线程的成本就会降至最低。但是,由某个线程运行的可运行对象被串行执行,而不是以并行方式执行。不理解?

    Java里面线程池的顶级接口是Executors,但是严格意义上讲Executor并不是一个线程池,而只是一个执行线程的工具。真正的线程池接口是ExecutorService。下面这张图完整描述了线程池的类体系结构。】

    固定大小的线程池:

    import java.util.concurrent.Executors;
    import java.util.concurrent.ExecutorService;
    public class JavaThreadPool {
        public static void main(String[] args) {
        // 创建一个可重用固定线程数的线程池
        ExecutorService pool = Executors.newFixedThreadPool(2);
        // 创建实现了Runnable接口对象,Thread对象当然也实现了Runnable接口
        Thread t1 = new MyThread();
        Thread t2 = new MyThread();
        Thread t3 = new MyThread();
        Thread t4 = new MyThread();
        Thread t5 = new MyThread();
        // 将线程放入池中进行执行
        pool.execute(t1);
        pool.execute(t2);
        pool.execute(t3);
        pool.execute(t4);
        pool.execute(t5);
        // 关闭线程池
        pool.shutdown();
        }
    }
    class MyThread extends Thread {
        @Override
        public void run() {
        System.out.println(Thread.currentThread().getName() + "正在执行。。。");
        }
    }

    单任务线程池:

    //创建一个使用单个 worker 线程的 Executor,以无界队列方式来运行该线程。 
    
    ExecutorService pool = Executors.newSingleThreadExecutor(); 

    对于以上两种连接池,大小都是固定的,当要加入的池的线程(或者任务)超过池最大尺寸时候,则入此线程池需要排队等待。一旦池中有线程完毕,则排队等待的某个线程会入池执行。

     参考http://www.cnblogs.com/jersey/archive/2011/03/30/2000231.html

     线程的终止 

       线程的run方法终止,线程就终止。

       线程应该负责终止其线程。(可能多个线程共享对象时,停止一个线程可能导致危险,应该用通知应被终止线程的方式来取代简单地停止线程。该线程通过释放它正在使用的资源并完成任何其他所需清理的工作来协作。)

     为通知线程它应该清理并终止。要是有interrupt方法

    t.interrupt(); 该方法是将不能造成该线程终止,它只是在线程的数据结构中设置一个boolean字段。

     通过调研interrupted方法,run方法能够检查线程是否已被中断。

    The run method can check whether that flag has been set, by calling the static interrupted method. In that case, it should do any necessary cleanup and exit. For example, the run method of the GreetingRunnable could check for interruptions at the  beginning of each loop iteration:

    public void run()
    {
    for (int i = 1;i <= REPETITIONS && !Thread.interrupted(); i++)
    {
    Do work
    }
    Clean up
    }

     但是,如果线程正在休眠,那么它就不能执行检查中断的代码。因此,只要休眠线程被中断,sleep方法就会用InterruptedException 异常来终止。当sleep方法在已被中断的线程中被调用时,也会抛出此异常。如果自己的run方法在每次循环时都调用sleep,就使用InterruptedException 造成线程是否被终止。实现此目的最简单的方式是,用try 块围住run方法的整个工作部分。类似:

    public void run()
    {
    try
    {
    for (int i = 1; i <= REPETITIONS; i++)
    {
    Do work
    Sleep
    }
    }
    catch (InterruptedException exception)
    {
    }
    Clean up
    }

    在线程的run方法中检测线程中断

      只需将线程的动作放入捕获InterruptedException异常的try块内即可。不处于运行状态的线程被中断时,该异常就会发生。

    By convention, a thread should terminate itself (or at least act in some other well-defined way) when it is interrupted. You should implement your threads to follow this convention.
         Simply put the thread action inside a try block that catches the InterruptedException. Thatexception occurs when your thread is interrupted while it is not running, for example inside  a call to sleep. When you catch the exception, do any required cleanup and exit the run
    method.
            Some programmers don’t understand the purpose of the InterruptedException and, out of  ignorance and desperation, muzzle it by surrounding only the call to sleep inside a try block.

    public void run()
    {
      while (. . .)
      {
        . . .
        try
        {
          Thread.sleep(delay);
        }
          catch (InterruptedException exception) {} // DON’T
        . . .
        }
    }

    这是错误的。

     Don’t do that. If you do, users of your thread class can’t get your thread’s attention by interrupting
    it. It is just as easy to place the entire thread action inside a single try block. Then interrupting the thread terminates the thread action.
     应该这样:

    public void run()
    {
    try
    {
    while (. . .)
    {
    . . .
    Thread.sleep(delay);
    . . .
    }
    }
    catch (InterruptedException exception) {} // OK

     

     

     

     

  • 相关阅读:
    C#基础之事件
    C#中IQueryable和IEnumerable的区别(2)
    读取不到appsettings.json的值
    【PHP】 延时跳转
    【canvas】 绘制七巧板
    小程序项目编译失败问提解决
    windows下安装node.js
    deskgenius分区失败,分区消失,解决的过程
    IOS:重写UISlider大小解决UISlider滑动不灵敏的问题
    IOS:reason: 'invalid nib registered for identifier (PhotoCellID)
  • 原文地址:https://www.cnblogs.com/youxin/p/2501623.html
Copyright © 2020-2023  润新知