Java基础 -- 线程2

Java线程2 --- Java线程状态?中断?基本的调度原则?

 

参考资料<<Java2核心技术,卷:高级性能 第五版>>

 

 

线程的状态

new()

       线程尚未运行。

runnable(可运行)

       调用了start方法。可运行可以是尚未运行。(指点了start方法后,可能还没有分配到时间片,或分配了时间片还没到此时间片)

blocked(被中断运行)

       有人调用该线程的sleep()方法

       该线程调用了一个输入/输出时中断的操作,也就是说,在输入和输出操作完成之前,该操作将不会返回到它的调用程序。

       该线称调用了wait()方法

       该线程试图锁定了一个当前被另一个线程锁定了的对象。

       有人调用了该线程的suspend()方法。但是现在该方法已经作废。并且在你的代码中你不应调用该方法。      

dead()

       由于run方法的正常退出而自然死亡。

       没有抓取到的异常事件终止了run方法的执行,从而导致线程的突然死亡。

 

PS:判断某个线程是否活着’(这里活着是指它是否处于可运行状态或者中断状态)。可使用isAlive方法。如果该线程是可运行线程或者被中断的线程,那么该方法将返回true,如果该线程仍然是个新线程或者尚未成为可运行线程,或者该线程是个死线程。那么该方法将返回false.

 

 

 

 

线程的中断

 

线程在不睡觉或者没有被中断的时候时候调用interrupt()方法不抛出InterruptedException()异常,只是设置中断标志!!!!!

 

PS:<<Java2核心技术,卷:高级性能 第五版>>书里第5行这样写 “如果在线程处于睡眠或者等待状态时调用interrupt方法,那么将不会产生任何InterruptException事件,该线程需要调用interrupted()来确定它最近是否被中断了” 这句话差点没把我害死,正好把情况写反了,害我看这一章花了好久时间,还摸不出个头绪来。看这本书同志注意了。

 

关于中断的几种代码框架:

 

1把中断解释为一个终止运行的请求。这种线程的run方法形式如下:

PS:这个框架有点小问题,就是线程在正常情况下调用interrupt()方法,线程不会退出,而只是把中断标志被设为true,表明被中断过,其实还跑的真欢呢)

public void run()

{

       Try

       {

             

              While ( more work to do)

              {

                     do more work

              }

       }

       catch ( InterruptedException exception)

       {

              // thread was interrupted during sleep or wait

       }

       finally

       {

              // Clean up

       }

       // exit method and terminate thread

}

 

2 上面的代码框架存在一个问题,如果在线程不处于睡眠或者等待状态时调用interrupt方法,那么将不会产生任何InterruptedException事件,该线程需要调用interrupted方法来确定它最近是否被中断了。

While(!interrupted() && more work to do

PS:这里interruptedisInterrupted两种判断线程是否被中断过的方法见下面的JDK的详细说明)

{

       Do more work;

}

 

3 sleep只定义为在发生中断时返回中断标志,那么这是最好的。这时根本不必使用InterruptedExcetption.当然,你可以在抓取到InterruptedException时,用人工方法设置中断标志:

(PS: 因为线程在不睡觉或者没有被中断的时候时候调用interrupt()方法不抛出InterruptedException()异常,只是设置中断标志)

Try

{

       Sleep(delay);

}

catch(InterruptedException exception)

{

       Thread.currentThread().interrupt();

}

如果是通过一个不能产生任何异常事件的方法来调用sleep方法,那么必须使用上面这种方法。

 

4 中断标志转换成一个异常事件

PS:因为线程在不睡觉或者没有被中断的时候时候调用interrupt()方法不抛出InterruptedException()异常,而只是把中断标志设为true,

见下面interrupt方法的详细定义,这样子程序不会被中断,所以我们可以在程序中插入下面这行代码,一旦中断标志为true,手工抛出异常让程序终止。

   if (isInterrupted()) throw new InterruptedException()

 

 

interrupt

public void interrupt()

中断线程。

如果当前线程没有中断它自己(这在任何情况下都是允许的),则该线程的 checkAccess 方法就会被调用,这可能抛出 SecurityException

如果线程在调用 Object 类的 wait()wait(long) wait(long, int) 方法,或者该类的 join()join(long)join(long, int)sleep(long) sleep(long, int) 方法过程中受阻,则其中断状态将被清除,它还将收到一个 InterruptedException

如果该线程在可中断的通道上的 I/O 操作中受阻,则该通道将被关闭,该线程的中断状态将被设置并且该线程将收到一个 ClosedByInterruptException

如果该线程在一个 Selector 中受阻,则该线程的中断状态将被设置,它将立即从选择操作返回,并可能带有一个非零值,就好像调用了选择器的 wakeup 方法一样。

如果以前的条件都没有保存,则该线程的中断状态将被设置(为true)。

抛出:

SecurityException - 如果当前线程无法修改该线程


public class InterruptedException

extends Exception

当线程在很长一段时间内一直处于正在等待、休眠或暂停状态,而另一个线程用 Thread 类中的 iterrupt 方法中断它时,抛出该异常。

 


interrupted

public static boolean interrupted()

测试当前线程是否已经中断。线程的中断状态 由该方法清除。换句话说,如果连续两次调用该方法,则第二次调用将返回 false(在第一次调用已清除了其中断状态之后,且第二次调用检验完中断状态前,当前线程再次中断的情况除外)。

返回:

如果当前线程已经中断,则返回 true;否则返回 false

另请参见:

isInterrupted()

 


isInterrupted

public boolean isInterrupted()

测试线程是否已经中断。线程的中断状态 不受该方法的影响。

返回:

如果该线程已经中断,则返回 true;否则返回 false

另请参见:

interrupted()

 

 

基本的调度原则

 

(下面这5个原则摘录自<<Java2核心技术,卷:高级性能 第五版>>第一章

调度原则确实是很复杂的,不过使用起来实际上是相当简单的,你只需要按照下面这5个原则进行操作即可:

1)  如果两个或多个线程修改一个对象,请将执行修改的方法声明为synchronized方法,受到对象修改影响的只读方法也必须实现同步。

2)  如果一个线程必须等待某个对象的状态出现变更,那么它应该在对象的内部等待,而不是在外边等待,这可通过输入一个synchronized方法,并且调用wait方法来实现。

3)  不要在synchronized方法中花费大量的时间。大多数操作只是更新数据结构,然后很快返回。如果你不能立即完成synchronized方法的操作。那么请调用wait方法,这样你可以在等待时释放该对象锁。

4)  每当一个方法改变某个对象的状态时,它就应该调用notifyAll方法,这样可以给等待线程一个机会,以便查看环境有没有发生变化。

5)  请记住,waitnotifyAll/notify方法都属于Object类的方法,而不是Thread类的方法,请反复检查你对wait方法的调用与同一个对象上的通知是否匹配。

 

(PS:上面几条都很好理解,就第3 那么它应该在对象的内部等待,而不是在外边等待不怎么明白,这里指的在外面等待是什么?)

 

 

 

几个小例子,可以直接运行,研究下对刚学习线程的朋友应该很有帮助的:

打印当前所有线程的例子,可以直接放在程序查看当前活动线程。很有用。

public class ThreadLister {

  private static void printThreadInfo(Thread t, String indent) {

    if (t == null)

      return;

    System.out.println(indent + "Thread: " + t.getName() + "  Priority: "

        + t.getPriority() + (t.isDaemon() ? " Daemon" : "")

        + (t.isAlive() ? "" : " Not Alive"));

  }

 

  /** Display info about a thread group */

  private static void printGroupInfo(ThreadGroup g, String indent) {

    if (g == null)

      return;

    int numThreads = g.activeCount();

    int numGroups = g.activeGroupCount();

    Thread[] threads = new Thread[numThreads];

    ThreadGroup[] groups = new ThreadGroup[numGroups];

 

    g.enumerate(threads, false);

    g.enumerate(groups, false);

 

    System.out.println(indent + "Thread Group: " + g.getName()

        + "  Max Priority: " + g.getMaxPriority()

        + (g.isDaemon() ? " Daemon" : ""));

 

    for (int i = 0; i < numThreads; i++)

      printThreadInfo(threads[i], indent + "    ");

    for (int i = 0; i < numGroups; i++)

      printGroupInfo(groups[i], indent + "    ");

  }

 

  /** Find the root thread group and list it recursively */

  public static void listAllThreads() {

    ThreadGroup currentThreadGroup;

    ThreadGroup rootThreadGroup;

    ThreadGroup parent;

 

    // Get the current thread group

    currentThreadGroup = Thread.currentThread().getThreadGroup();

 

    // Now go find the root thread group

    rootThreadGroup = currentThreadGroup;

    parent = rootThreadGroup.getParent();

    while (parent != null) {

      rootThreadGroup = parent;

      parent = parent.getParent();

    }

 

    printGroupInfo(rootThreadGroup, "");

  }

 

  public static void main(String[] args) {

        

    ThreadLister.listAllThreads();

  }

}

 

一个死锁的例子

public class AnotherDeadLock {

  public static void main(String[] args) {

    final Object resource1 = "resource1";

    final Object resource2 = "resource2";

    // t1 tries to lock resource1 then resource2

    Thread t1 = new Thread() {

      public void run() {

        // Lock resource 1

        synchronized (resource2) {

          System.out.println("线程1取得resource1的锁");

          try {

            Thread.sleep(50);

          } catch (InterruptedException e) {

          }

                System.out.println("线程1尝试去取得resource1的锁");

                try{

                       sleep(1000);

                }catch(Exception e){

                }

          synchronized (resource1) {

            System.out.println("线程1取得了资源1的锁");

          }

                System.out.println("线程1释放了了资源1的锁");

        }

              System.out.println("线程1释放resource1的锁");

      }

 

         public void release(){

              notifyAll();

         }

    };

 

    // t2 tries to lock resource2 then resource1

    Thread t2 = new Thread() {

      public void run() {

        synchronized (resource1) {

          System.out.println("线程2取得resource2的锁");

 

          try {

            Thread.sleep(50);

          } catch (InterruptedException e) {

          }

                System.out.println("线程2尝试去取得resource2的锁");

                try{

                       sleep(1000);

                }catch(Exception e){

                }

          synchronized (resource2) {

            System.out.println("线程2取得了资源2的锁");

          }

                System.out.println("线程2释放了资源2的锁");

        }

              System.out.println("线程2释放了资源2的锁");

      }

    };

 

    t1.start();

    t2.start();

  }

}

 

使用同步方法的程序,看看synchronized的用法。

public class OnlyOneInMethod extends Object {

  private String objID;

 

  public OnlyOneInMethod(String objID) {

    this.objID = objID;

  }

 

  public synchronized void doStuff(int val) {

    print("entering doStuff()");

    int num = val * 2 + objID.length();

    print("local variable num=" + num);

 

    try {

      Thread.sleep(2000);

    } catch (InterruptedException x) {

    }

 

    print("leaving doStuff()");

  }

 

  public void print(String msg) {

    threadPrint("objID=" + objID + " - " + msg);

  }

 

  public static void threadPrint(String msg) {

    String threadName = Thread.currentThread().getName();

    System.out.println(threadName + ": " + msg);

  }

 

  public static void main(String[] args) {

    final OnlyOneInMethod ooim = new OnlyOneInMethod("obj1");

 

    Runnable runA = new Runnable() {

      public void run() {

        ooim.doStuff(3);

      }

    };

 

    Thread threadA = new Thread(runA, "threadA");

    threadA.start();

 

    try {

      Thread.sleep(200);

    } catch (InterruptedException x) {

    }

 

    Runnable runB = new Runnable() {

      public void run() {

        ooim.doStuff(7);

      }

    };

 

    Thread threadB = new Thread(runB, "threadB");

    threadB.start();

 

       Runnable runC = new Runnable() {

      public void run() {

        ooim.doStuff(10);

      }

    };

 

    Thread threadC = new Thread(runC, "threadC");

    threadC.start();

  }

}

 

 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值