Java Thread及其synchronized,wait,sleep,join,yeid,interrupt

Java SE7 API - Thread:html

 http://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#yield%28%29java

参考资料:http://blog.csdn.net/lqqmisslll/article/details/54208491程序员

 

1、线程的简介api

      当JVM启动的时候, 一般会有一个独立的非守护线程(也就是类中的main方法所在的线程).JVM会继续运行,除非发生如下状况:安全

      Runtime类的exit()方法被调用,而且安全管理者容许退出发生。多线程

      全部非守护线程都已经死了,不论是从run方法中返回的仍是由于run方法中抛出了异常。并发

      注意:当全部非守护线程都执行结束(包括主线程),那么守护线程也会退出。由于守护线程是没法脱离非守护线程而独自存在的。oracle

2、建立线程有两种方式:app

        方法1:声明一个类做为Thread的子类(extends Thread),子类重写(override)Thread类的run()方法。子类的实例能够被分配和start。        jvm

    //好比:该线程用来计算比指定起始值大的素数。
    class PrimeThread extends Thread 
    {
         long minPrime;
         PrimeThread(long minPrime) 
         {
             this.minPrime = minPrime;
         }
         public void run() 
         {
             // compute primes larger than minPrime
              . . .
         }
     }
     //如下代码用来建立和启动线程PrimeThread 
     PrimeThread p = new PrimeThread(143);
     p.start();

  方法2: 声明一个实现Runnable接口的类(implements Runnable),该类实现run()方法。该类的实例能够被分配,或者在建立Thread时做为一个参数,而且start.

    class PrimeRun implements Runnable 
    {
         long minPrime;
         PrimeRun(long minPrime) 
         {
             this.minPrime = minPrime;
         }

         public void run() 
         {
             // compute primes larger than minPrime
              . . .
         }
     }
     PrimeRun p = new PrimeRun(143);
     new Thread(p).start();

        继承Thread与实现Runnable的区别:

  1. 实现 Runnable 大多数状况下是比继承 Thread 更好的方法。

  2. 1. Java 只支持单继承,因此你继承了 Thread 的话,其余的类你就不能继承了。

  3. 2. 若是实现 Runnable 接口,多线程能够直接将你的工做并发处理(直接使用 start)。而继承 Thread 不能直接进行多线程工做,你得为你的每一部分工做都定义一个线程。

  4. 3. 其余的一些API,接口都是 Runnable 类型的。好比 Java 内置的线程池 API ExcutorService 等。

3、线程的状态 
线程有四种状态,任何一个线程确定处于这四种状态中的一种: 
    1)产生(New):线程对象已经产生,但还没有被启动,因此没法执行。如经过new产生了一个线程对象后没对它调用start()函数以前。 
    2)可执行(Runnable):每一个支持多线程的系统都有一个排程器,排程器会从线程池中选择一个线程并启动它。当一个线程处于可执行状态时,表示它可能正处于线程池中等待排排程器启动它;也可能它已正在执行。如执行了一个线程对象的start()方法后,线程就处于可执行状态,但显而易见的是此时线程不必定正在执行中。 
    3)停滞(Blocked):当一个线程处于停滞状态时,系统排程器就会忽略它,不对它进行排程。当处于停滞状态的线程从新回到可执行状态时,它有可能从新执行。如经过对一个线程调用wait()函数后,线程就进入停滞状态,只有当两次对该线程调用notify或notifyAll后它才能两次回到可执行状态。

   4)死亡(Dead):当一个线程正常结束,它便处于死亡状态。如一个线程的run()函数执行完毕后线程就进入死亡状态。

3、Thread的方法:

static intactiveCount() Returns an estimate of the number of active threads in the current thread's thread group and its subgroups.
StringgetName() Returns this thread's name.
intgetPriority() Returns this thread's priority.
Thread.State getState() Returns the state of this thread.
booleanisAlive() Tests if this thread is alive.
booleanisDaemon() Tests if this thread is a daemon thread.
booleanisInterrupted() Tests whether this thread has been interrupted.

    最经常使用的方法

void join() Waits for this thread to die.
void join(long millis) Waits at most millis milliseconds for this thread to die.
void join(long millis, int nanos) Waits at most millis milliseconds plus nanos nanoseconds for this thread to die.
void run() If this thread was constructed using a separate Runnable run object, then that Runnable object's run method is called; otherwise, this method does nothing and returns.
void setDaemon(boolean on) Marks this thread as either a daemon thread or a user thread.
static void sleep(long millis) Causes the currently executing thread to sleep (temporarily cease execution) for the specified number of milliseconds, subject to the precision and accuracy of system timers and schedulers.
static void sleep(long millis, int nanos) Causes the currently executing thread to sleep (temporarily cease execution) for the specified number of milliseconds plus the specified number of nanoseconds, subject to the precision and accuracy of system timers and schedulers.
void start() Causes this thread to begin execution; the Java Virtual Machine calls the run method of this thread.
static void yield() A hint to the scheduler that the current thread is willing to yield its current use of a processor.
void interrupt()

Interrupts this thread.

If this thread is blocked in an invocation of the wait()wait(long), or wait(long, int) methods of the Object class, or of the join()join(long)join(long, int)sleep(long), or sleep(long, int), methods of this class, then its interrupt status will be cleared and it will receive an InterruptedException.

If this thread is blocked in an I/O operation upon an interruptible channel then the channel will be closed, the thread's interrupt status will be set, and the thread will receive aClosedByInterruptException.

If this thread is blocked in a Selector then the thread's interrupt status will be set and it will return immediately from the selection operation, possibly with a non-zero value, just as if the selector'swakeup method were invoked.

If none of the previous conditions hold then this thread's interrupt status will be set.

从java.long.Object继承来的方法:

‍ ‍ ‍ ‍

protected voidfinalize() Called by the garbage collector on an object when garbage collection determines that there are no more references to the object.
void notify() Wakes up a single thread that is waiting on this object's monitor.
void notifyAll() Wakes up all threads that are waiting on this object's monitor.
void wait() Causes the current thread to wait until another thread invokes the notify() method or the notifyAll()method for this object.
void wait(long timeout) Causes the current thread to wait until either another thread invokes the notify() method or thenotifyAll() method for this object, or a specified amount of time has elapsed.
void wait(long timeout, int nanos) Causes the current thread to wait until another thread invokes the notify() method or the notifyAll()method for this object, or some other thread interrupts the current thread, or a certain amount of real time has elapsed.

注意事项

1.sleep-wait-yield区别

    sleep是Thread类中的一个静态方法,在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操做受到系统计时器和调度程序精度和准确性的影响,若是指定睡眠的时间到达,则从阻塞状态转变成就绪状态,等待运行。 
    yield只是使当前线程放弃执行权(从新回到可执行状态),让其它同一优先级的线程先运行,因此执行yield()的线程有可能进入到可执行状态后立刻又被执行。 

    wait是Object类中定义的方法,与notify/notifyAll()在一块儿成对使用,提供线程间的等待-通知机制。 

2.使用wait-notify 
    (1)调用notify是随机的唤醒某一thread.而notifyAll则是唤醒全部等待的线程, 但只有一个线程能够在唤醒后lock object monitor,因此, notifyAll操做也是有利弊的. 
    (2)wait、notify、notifyAll必须在synchronized修饰的代码块中执行,不然会在运行的时候抛出IllegalMonitorStateException 异常 .

    (3)在循环语句wait的时候必定要设定循环的条件(while(flag))--这样可以避免wait开始以前,线程所需的条件已经被其余线程提供了却依然开始此线程wait致使的时间消耗。同时,这种办法还可以保证你的代码不被虚假的信息唤醒。 
    (4)老是要保证在调用notify和notifyAll以前,可以提供符合线程退出等待的条件。不然会出现即便线程接收到通知信息,却不能退出循环等待的状况。 

3.join()方法 
  join方法是使当前线程阻塞,直到所引用的线程结束才激活. 

 

4、实现线程同步的方法

1.有synchronized关键字的同步方法
    synchronized有四种使用方式: 
         synchronized method(){} 
      synchronized (obj) 
      static synchronized method(){} 
      synchronized(classname.class) 

   前面两个使用的锁是对象monitor,后面二者使用的是类monitor,均可以实现互斥访问。 
一个对象只有一个对象monitor,一个类也只有一个类monitor。静态方法使用类monitor进行同步,而普通方法则使用对象monitor进行同步。

2.使用lock()与unlock()之间的同步块。

代码示例:

  1.经过setDaemon(true)将鲜橙设置为守护线程,以及守护线程的特色。

public class Counter
{
    public AtomicInteger  inc = new AtomicInteger();
    public void increase()
    {
        inc.getAndIncrement();
    }
    public static void main(String[] args) throws InterruptedException
    {
        final Counter test = new Counter();
        for (int i = 0; i < 10; i++)
        {
            Thread t = new Thread()
            {
                @Override
                public void run()
                {
                    for (int j = 0; j < 10; j++)
                    {
                        test.increase();
                        System.out.println(Thread.currentThread().getName() + "----" + test.inc);
                    }
                };
            };
//            t.setDaemon(true);
            t.start();            
        }       
        
        while (Thread.activeCount() > 1)//保证前面的线程都执行完
        {
//            Thread.yield();
//            Thread.sleep(1);
//            System.out.println(Thread.currentThread().getName()+"-yield");
        }        
        System.out.println(test.inc);
        System.out.println("Thread.activeCount()="+Thread.activeCount());
    }
}

   经过启用注释掉的部分能够获得不一样的结果。

   2. 使用join()控制线程执行顺序:http://my.oschina.net/liuyuanyuangogo/blog/315927

   3. 使用interrupt()方法控制线程的中止:

/**
 *
 * @author Yuanyuan
 * 终止线程的方法
 * stop()方法不安全,已启用。
 * 如何终止线程?
 * 终止线程的方法只有一个,就是让run()方法运行结束.
 * 
 * 开启多线程运行时,运行代码一般是循环结构。
 * 只要控制住循环,就可让run方法结束,也就是该线程结束。(一般会用一个标记变量来控制)
 * 
 * 特殊状况,
 * 当线程处于冻结状态。就不会读取到标记,那线程就没法结束。
 *  
 * 当没有指定的方式让冻结的线程回复到运行状态,这是须要对冻结进行清除。
 * 强制让线程恢复到运行中来,这样就能够操做标记让线程结束。
 * Thread类提供了方法interrupt()
 * 
 */
class StopThread extends Thread
{
    private boolean flag = true;
    @Override
    public synchronized  void run()
    {
        while(flag)
        {
            try
            {
                this.wait();
            } catch (InterruptedException ex)
            {
                System.out.println(Thread.currentThread().getName()+"---Exception");
                flag = false;
            }
        }
        System.out.println(Thread.currentThread().getName()+"---run");
    }
}
public class ThreadDemo
{
    public static void main(String[] args)
    {
        Thread t1 = new StopThread();
        Thread t2 = new StopThread();
        t1.start();
        t2.start();
        for(int i=0;i<10;i++)
        {
            if(i==5)
            {
                t1.interrupt();//
                t2.interrupt();
            }
            System.out.println(Thread.currentThread().getName()+"---"+i);
        }        
    }
}

举例说明Thread与Runnable的区别:

(如下转自:http://mars914.iteye.com/blog/1508429

 在实际应用中,咱们常常用到多线程,如车站的售票系统,车站的各个售票口至关于各个线程。当咱们作这个系统的时候可能会想到两种方式来实现,继承Thread类或实现Runnable接口,如今看一下这两种方式实现的两种结果。

  1. package com.threadtest;  
    class MyThread extends Thread
    {
        private int ticket = 10;  
        private String name;  
        public MyThread(String name)
       {  
            this.name =name;  
        }  
        public void run()
       {  
            for(int i =0;i<500;i++)
            {  
                if(this.ticket>0)
                {  
                    System.out.println(this.name+"卖票---->"+(this.ticket--));  
                }  
            }  
        }  
    }  
    public class ThreadDemo {       
        public static void main(String[] args) {  
            MyThread mt1= new MyThread("一号窗口");  
            MyThread mt2= new MyThread("二号窗口");  
            MyThread mt3= new MyThread("三号窗口");  
            mt1.start();  
            mt2.start();  
            mt3.start();  
        }  
    }

运行结果以下:

  1. 一号窗口卖票---->10  
    一号窗口卖票---->9  
    二号窗口卖票---->10  
    一号窗口卖票---->8  
    一号窗口卖票---->7  
    一号窗口卖票---->6  
    三号窗口卖票---->10  
    一号窗口卖票---->5  
    一号窗口卖票---->4  
    一号窗口卖票---->3  
    一号窗口卖票---->2  
    一号窗口卖票---->1  
    二号窗口卖票---->9  
    二号窗口卖票---->8  
    三号窗口卖票---->9  
    三号窗口卖票---->8  
    三号窗口卖票---->7  
    三号窗口卖票---->6  
    三号窗口卖票---->5  
    三号窗口卖票---->4  
    三号窗口卖票---->3  
    三号窗口卖票---->2  
    三号窗口卖票---->1  
    二号窗口卖票---->7  
    二号窗口卖票---->6  
    二号窗口卖票---->5  
    二号窗口卖票---->4  
    二号窗口卖票---->3  
    二号窗口卖票---->2  
    二号窗口卖票---->1

 

经过实现Runnable接口的代码以下:

  1. class MyThread1 implements Runnable{  
        private int ticket =10;  
        private String name;  
        public void run(){  
            for(int i =0;i<500;i++){  
                if(this.ticket>0){  
                    System.out.println(Thread.currentThread().getName()
                    +"卖票---->"+(this.ticket--));  
                }  
            }  
        }  
    }  
    public class RunnableDemo 
    {        
        public static void main(String[] args)  
        {      
            // TODO Auto-generated method stub  
            //设计三个线程  
             MyThread1 mt = new MyThread1();  
             Thread t1 = new Thread(mt,"一号窗口");  
             Thread t2 = new Thread(mt,"二号窗口");  
             Thread t3 = new Thread(mt,"三号窗口");  
    //         MyThread1 mt2 = new MyThread1();  
    //         MyThread1 mt3 = new MyThread1();  
             t1.start();  
             t2.start();  
             t3.start();  
        }  
      
    }

 运行结果以下:

  1. 一号窗口卖票---->10  
    三号窗口卖票---->9  
    三号窗口卖票---->7  
    三号窗口卖票---->5  
    三号窗口卖票---->4  
    三号窗口卖票---->3  
    三号窗口卖票---->2  
    三号窗口卖票---->1  
    一号窗口卖票---->8  
    二号窗口卖票---->6

    为何会出现这种结果呐。咱们不妨作个比喻,其实刚的程序,

继承Thread类的,咱们至关于拿出三件事即三个卖票10张的任务分别分给三个窗口,他们各作各的事各卖各的票各完成各的任务,由于MyThread继承Thread类,因此在new MyThread的时候在建立三个对象的同时建立了三个线程;

实现Runnable的, 至关因而拿出一个卖票10张得任务给三我的去共同完成,new MyThread至关于建立一个任务,而后实例化三个Thread,建立三个线程即安排三个窗口去执行。

用图表示以下:

    在咱们刚接触的时候可能会迷糊继承Thread类和实现Runnable接口实现多线程,其实在接触后咱们会发现这彻底是两个不一样的实现多线程,一个是多个线程分别完成本身的任务,一个是多个线程共同完成一个任务。

    其实在实现一个任务用多个线程来作也能够用继承Thread类来实现只是比较麻烦,通常咱们用实现Runnable接口来实现,简洁明了。      

    大多数状况下,若是只想重写 run() 方法,而不重写其余 Thread 方法,那么应使用 Runnable 接口。这很重要,由于除非程序员打算修改或加强类的基本行为,不然不该为该类(Thread)建立子类。

 

Difference between Thread vs Runnable interface in Java

   Thread vs Runnable  in Java  is always been a confusing decision for beginner s    in  java.  Thread in Java  seems easy in comparison of Runnable because you just deal with one class  java.lang.Thread  while in case of using Runnable to implement Thread you need to deal with both Thread and Runnable two classes. though decision of using Runnable or Thread should be taken considering differences between Runnable and Thread and pros and cons of both approaches. This is also a very  popular thread interview questions  and most of interviewer are really interested to know what is your point of view while choosing Thread vs Runnable or opposite. In this java article we will try to point out some differences between Thread and Runnable in Java which will help you to take an informed  decision. 

    Thread vs Runnable in Java

Here are some of my thoughts on whether I should use Thread or Runnable for implementing task in Java, though you have another choice as " Callable " for implementing thread which we will discuss later.

‍1)  Java doesn't support multiple inheritance , which means you can only extend one class in Java so on c e you extend ed  Thread class you lost your chance and   can not extend or inherit another  class in Java .‍

2) In Object oriented programming extending a class generally means adding new functionality, modifying or improving behaviors. If we are not making any modification on Thread than use Runnable interface instead.

3) Runnable interface represent a Task which can be executed by either plain  Thread  or  Executors  or any other means. so logical separation of Task as   Runnable  than Thread is good design decision.

4) Separating task as Runnable means we can reuse the task and also has liberty to execute it from different means. since you can not restart a Thread once it completes. again Runnable vs Thread for task, Runnable is winner.

5) Java designer recognizes this and that's why Executors accept Runnable as Task and they have worker thread which executes those task.

    6) Inheriting all Thread methods are additional overhead just for representing a Task which can can be done easily with Runnable.

    These were some of notable difference between Thread and Runnable in Java, if you know any other differences on Thread vs Runnable than please share it   via comments. I personally use Runnable over Thread for this scenario and recommends to use Runnable or Callable interface based on your requirement.

    Some more Java Tutorials you may like

    Why Wait and Notify in Java is called from Synchronized context

    Difference between Comparator and Comparable in Java

    Difference between Wait, Sleep and yield in Java

    How to Stop Thread in Java with Code Example

    How to sort ArrayList in Java with Example

    Why Main is static in Java

    Difference between JVM, JRE and JDK in Java

 

Read more: 

http://javarevisited.blogspot.com/2012/01/difference-thread-vs-runnable-interface.html#ixzz3Ctqfnhpz

相关文章
相关标签/搜索