Thread类简单介绍

Thread.State的状态

jdk中关于线程状态的描述:

public enum State {
        /**
         * Thread state for a thread which has not yet started.
         */
        NEW,

        /**
         * Thread state for a runnable thread.  A thread in the runnable
         * state is executing in the Java virtual machine but it may
         * be waiting for other resources from the operating system
         * such as processor.
         */
        RUNNABLE,

        /**
         * Thread state for a thread blocked waiting for a monitor lock.
         * A thread in the blocked state is waiting for a monitor lock
         * to enter a synchronized block/method or
         * reenter a synchronized block/method after calling
         * {@link Object#wait() Object.wait}.
         */
        BLOCKED,

        /**
         * Thread state for a waiting thread.
         * A thread is in the waiting state due to calling one of the
         * following methods:
         * <ul>
         *   <li>{@link Object#wait() Object.wait} with no timeout</li>
         *   <li>{@link #join() Thread.join} with no timeout</li>
         *   <li>{@link LockSupport#park() LockSupport.park}</li>
         * </ul>
         *
         * <p>A thread in the waiting state is waiting for another thread to
         * perform a particular action.
         *
         * For example, a thread that has called <tt>Object.wait()</tt>
         * on an object is waiting for another thread to call
         * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
         * that object. A thread that has called <tt>Thread.join()</tt>
         * is waiting for a specified thread to terminate.
         */
        WAITING,

        /**
         * Thread state for a waiting thread with a specified waiting time.
         * A thread is in the timed waiting state due to calling one of
         * the following methods with a specified positive waiting time:
         * <ul>
         *   <li>{@link #sleep Thread.sleep}</li>
         *   <li>{@link Object#wait(long) Object.wait} with timeout</li>
         *   <li>{@link #join(long) Thread.join} with timeout</li>
         *   <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
         *   <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
         * </ul>
         */
        TIMED_WAITING,

        /**
         * Thread state for a terminated thread.
         * The thread has completed execution.
         */
        TERMINATED;
    }

  1. New:新创建的一个线程对象
  2. Runnable:就绪状态,线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于"可运行线程池"中,变得可运行,此时等待操作系统的其他资源,比如处理器
  3. TimedWaiting:等待特定的时间,调用下面函数时,线程处于该状态
  • Thread.sleep
  • Object.wait with timeout (有参数的)
  • Thread.join with timeout
  • LockSupport.parkNanos
  • LockSupport.parkUntil
  1. WAITING:等待,调用下面参数时,该线程处于该状态
  • Object.wait with no timeout
  • Thread.join with no timeout
  • LockSupport.park
  1. BLOCKED:阻塞状态,当其他线程调用Object.wait后,若该线程要进入同样的synchronized块,则该线程状态变为阻塞状态
  2. TERMINATED:线程执行结束,变为该状态
    package zt.thread;
    import java.util.ArrayList;
    import java.util.List;
    /**
     * <p>标题:模拟生产者消费者</p>
     * <p>描述:生产者少,消费者多,并且生产慢,那么就会产生阻塞</p>
     * <p>编译者:zt</p>
     */
    public class Plate {
    	private List<Object> eggs = new ArrayList<Object>();
    	public synchronized void getEgg() throws InterruptedException{
    		while(eggs.size() == 0) {
    			wait();
    		}
    		eggs.remove(0);
    		System.out.println("消费一个鸡蛋,当前还剩: " + eggs.size());
    		notifyAll();
    	}
    
    	public synchronized void putEgg() throws InterruptedException {
    		while(eggs.size() == 1000000){
    			wait();
    		}
    		eggs.add(new Object());
    		Thread.sleep(200);
    		System.out.println("添加一个鸡蛋,当前还剩: " + eggs.size());
    		notifyAll();
    	}
    	public static void main(String[] args) {
    		Plate plant = new Plate();
    		//生产线程
    		for(int i = 0; i < 2; i++) {
    			new Thread(new Runnable(){
    				public void run() {
    					try {
    						while(true){
    							plant.putEgg();
    						}
    					} catch (InterruptedException e) {
    						e.printStackTrace();
    					}
    				}
    			}, "putegg"+i).start();
    		}
    		//消费线程
    		for(int i = 0; i < 3; i++) {
    			new Thread(new Runnable(){
    				public void run() {
    					try {
    						while(true){
    							plant.getEgg();
    						}
    					} catch (InterruptedException e) {
    						e.printStackTrace();
    					}
    				}
    			}, "getegg"+i).start();
    		}
    	}
    }

使用工具查看:

在dos命令中使用:

  • jps查看进程号:

  • 使用jstack查看线程状态,可以看到,有的线程被阻塞,有的处于TIMEWAITING中

常用函数

  1. 中断:
  • public void interrupt() // 中断线程
  • public boolean isInterrupted() // 判断是否被中断
  • public static boolean interrupted() // 判断是否被中断,并清除当前中断状态

调用Interrupted,不会中断一个正在运行的线程。线程会不时的检测中断标志位以判断线程是否应该被中断(中断标识值是否为true),中断只会影响到wait状态、sleep状态、join状态。被打断的线程会抛出InterruptedException。

如果在正常运行的程序中添加while(!Thread.interrupted()),则同样可以在中断后离开代码体。

jdk中关于这三者的描述:

中断线程,只是设置中断标志。

public void interrupt() {
	if (this != Thread.currentThread())
		checkAccess();

	synchronized (blockerLock) {
		Interruptible b = blocker;
		if (b != null) {
			interrupt0(); // Just to set the interrupt flag
			b.interrupt(this);
			return;
		}
	}
	interrupt0();
}

    判断是否被中断,并清除中断位:

public static boolean interrupted() {
	return currentThread().isInterrupted(true);
}

    判断是否被中断:

/**
 * Tests whether this thread has been interrupted. The <i>interrupted
 * status</i> of the thread is unaffected by this method.
 *
 * <p>A thread interruption ignored because a thread was not alive
 * at the time of the interrupt will be reflected by this method
 * returning false.
 *
 * @return <code>true</code> if this thread has been interrupted;
 * <code>false</code> otherwise.
 * @see #interrupted()
 * @revised 6.0
 */
public boolean isInterrupted() {
	return isInterrupted(false);
}
/**
 * Tests if some Thread has been interrupted. The interrupted state
 * is reset or not based on the value of ClearInterrupted that is
 * passed.
 */
private native boolean isInterrupted(boolean ClearInterrupted);
2. stop函数:这个方法并不安全,若当前的线程获得了monitor,正在执行,使用stop会直接释放monitor,那么就有可能导致数据不一致。
package zt.thread1;
/** 
 * <p>标题:测试stop函数</p>
 * <p>描述:执行stop有时会导致数据不一致</p>
 * <p>编译者:zt</p>
 */
public class ThreadStopTest {

    public static void main(String[] args) {
        Class1 class1 = new Class1();
        Thread test = new Thread(new Runnable(){
            public void run(){
                class1.update();
            }
        });
        test.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        test.stop();
        System.out.println(class1.toString());
        
    }
}
class Class1 {
    int i = 0;
    int j = 0;
    public synchronized void update(){
        i = 1;
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        j = 1;
    }
    public String toString(){
        return "i = " + i + "; j = " + j;
    }
}

上面例子的执行结果是:

解决方式与中断的方式类似:可以设置一个标识,不断去查询这个标识值是否发生了改变。这个例子没有那么合适,因为在循环体中会不断的去执行更新操作。

package zt.thread1;
/** 
 * <p>标题:测试替代stop函数</p>
 * <p>描述:执行stop有时会导致数据不一致</p>
 * <p>编译者:zt</p>
 */
public class ThreadReplaceStopTest {

    public static void main(String[] args) {
        Class2 class2 = new Class2();
        ReplaceStopThread test = new ReplaceStopThread(class2);
        test.start();
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        test.stop1();
        System.out.println(class2.toString());
    }
}
class ReplaceStopThread extends Thread {
    private volatile Thread blinker;
    Class2 class2;
    public ReplaceStopThread(Class2 class2){
        this.class2 = class2;
    }
    public void stop1() {
        blinker = null;
    }
    public void run() {
        Thread thisThread = Thread.currentThread();
        blinker = Thread.currentThread();
        while (blinker == thisThread) {
            class2.update();
            Thread.yield();
        }
    }
}
class Class2 {
    int i = 0;
    int j = 0;
    public synchronized void update(){
        i = 1;
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        j = 1;
        System.out.println("changeall");
    }
    public String toString(){
        return "i = " + i + "; j = " + j;
    }
} 
3. suspend(挂起) 与resume(继续执行) 函数

若线程没有suspend的情况下就执行resume方法会抛出异常。在调用suspend前就调用resume,那么线程就会一直挂起,如果还有锁那么就会死锁。suspend()不会释放锁

   
/**
     * Suspends this thread.
     * <p>
     * First, the <code>checkAccess</code> method of this thread is called
     * with no arguments. This may result in throwing a
     * <code>SecurityException </code>(in the current thread).
     * <p>
     * If the thread is alive, it is suspended and makes no further
     * progress unless and until it is resumed.
     *
     * @exception  SecurityException  if the current thread cannot modify
     *               this thread.
     * @see #checkAccess
     * @deprecated   This method has been deprecated, as it is
     *   inherently deadlock-prone.  If the target thread holds a lock on the
     *   monitor protecting a critical system resource when it is suspended, no
     *   thread can access this resource until the target thread is resumed. If
     *   the thread that would resume the target thread attempts to lock this
     *   monitor prior to calling <code>resume</code>, deadlock results.  Such
     *   deadlocks typically manifest themselves as "frozen" processes.
     *   For more information, see
     *   <a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">Why
     *   are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>.
     */
    @Deprecated
    public final void suspend() {
        checkAccess();
        suspend0();
    }
当调用suspend后,线程仍然处于RUNNABLE状态:
/** 
 * <p>标题:测试线程suspend函数</p>
 * <p>描述:</p>
 * <p>编译者:zt</p>
 */
public class ThreadSuspendTest {

	public static void main(String[] args) {
		Thread t1 = new Thread(new Runnable(){
			public void run(){
				try {
					Thread.sleep(3000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		},"t1");
		t1.start();
		t1.suspend();
	}
}

使用jsack查看此时的t1线程状态,处于RUNNABLE:

4. join函数:本质是不断的调用wait(0),当线程执行完成后,系统内部会调用notifyAll()函数。

jdk中的描述:

/**
     * Waits for this thread to die.
     *
     * <p> An invocation of this method behaves in exactly the same
     * way as the invocation
     *
     * <blockquote>
     * {@linkplain #join(long) join}{@code (0)}
     * </blockquote>
     *
     * @throws  InterruptedException
     *          if any thread has interrupted the current thread. The
     *          <i>interrupted status</i> of the current thread is
     *          cleared when this exception is thrown.
     */
    public final void join() throws InterruptedException {
        join(0);
    }
public final synchronized void join(long millis)
    throws InterruptedException {
        long base = System.currentTimeMillis();
        long now = 0;

        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (millis == 0) {
            while (isAlive()) {
                wait(0);
            }
        } else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }
5. yield函数:一旦执行,会使当前线程让出CPU,当前线程让出CPU后,还会进行CPU资源的争夺。
    /**
     * A hint to the scheduler that the current thread is willing to yield
     * its current use of a processor. The scheduler is free to ignore this
     * hint.
     *
     * <p> Yield is a heuristic attempt to improve relative progression
     * between threads that would otherwise over-utilise a CPU. Its use
     * should be combined with detailed profiling and benchmarking to
     * ensure that it actually has the desired effect.
     *
     * <p> It is rarely appropriate to use this method. It may be useful
     * for debugging or testing purposes, where it may help to reproduce
     * bugs due to race conditions. It may also be useful when designing
     * concurrency control constructs such as the ones in the
     * {@link java.util.concurrent.locks} package.
     */
    public static native void yield();

多线程异常的捕获

package zt.thread1;

import java.lang.Thread.UncaughtExceptionHandler;

/** 
 * <p>标题:获得线程异常</p>
 * <p>描述:</p>
 * <p>编译者:zt</p>
 */
public class GetThreadException {

    public static void main(String[] args) {
        
        try{
            new Thread(new Runnable(){
                public void run() {
                    int i = 1/0;
                }
            }, "testThread1").start();
        }catch(Exception e){
            System.out.println("testThread1 捕获异常");
        }
        Thread testThread2 = new Thread(new Runnable(){
            public void run() {
                int i = 1/0;
            }
        });
        testThread2.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
            public void uncaughtException(Thread t, Throwable e) {
                System.out.println("testThread2捕获异常");
            }
        });
        testThread2.start();
    }
}

此外,通过查看jdk源码发现,异常还与defaultUncaughtExceptionHandler、ThreadGroup有关。



参考

   《实战Java高并发程序设计》   --葛一鸣  郭超

猜你喜欢

转载自blog.csdn.net/baidu_14922873/article/details/79445177