Java中的多线程--Thread类

时间:2019-02-17
本文章向大家介绍Java中的多线程--Thread类,主要包括Java中的多线程--Thread类使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

本篇介绍Thread类中的一些方法.

构造器

Thread()   
Thread(Runnable target)   
Thread(Runnable target, String name)   
Thread(String name)  
Thread(ThreadGroup group, Runnable target) 
Thread(ThreadGroup group, Runnable target, String name)   
Thread(ThreadGroup group, Runnable target, String name, long stackSize)   
Thread(ThreadGroup group, String name) 

Runnable target:一个实现了Runnable接口的对象.
String name:名称.
ThreadGroup group:线程组.
long stackSize:堆栈大小.

方法

中断方法

Thread类中有3个非常相似的方法:

void interrupt()
中断该线程,线程中断状态设置为true.
static boolean interrupted()
测试当前线程(正在执行这个方法的线程)是否被中断,有附加效果:线程中断状态会被设置为false.
boolean islnterrupted()
测试线程是否被终止.不改变线程的中断状态.

分别看看这三个方法的源码:

interrupt():

    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);    //sun.nio.ch.Interruptible中的方法
                return;
            }
        }
        interrupt0();        //私有本地方法.
    }

    private native void interrupt0();

interrupted():

    public static boolean interrupted() {
        return currentThread().isInterrupted(true);//调用私有本地方法,参数为是否清除中断状态.
    }

    private native boolean isInterrupted(boolean ClearInterrupted);

 currentThread():获取当前线程并返回.

    public static native Thread currentThread();

islnterrupted():

    public boolean isInterrupted() {
        return isInterrupted(false); //是否清除中断状态:false.
    }

可以看到,interrupt()就是把线程中断,需要注意的是,如果当前线程处于阻塞状态(如被调用wait()或sleep()),就会抛出InterruptedException.

而interrupted()与isInterrupted()的区别在于是否是静态方法,和调用私有本地方法isInterrupted()时传入的参数,介绍时说道interrupted()会清除中断状态,就是将这个参数设为了true.isInterrupted()则设置为false.

Thread.sleep()时调用interrupt():

public class InterruptTest extends Thread{
    public static void main(String[] args) throws InterruptedException{
        Thread t = new Inter();
        t.start();
        t.interrupt();
    }
}

class Inter extends Thread{
    @Override
    public void run() {
        System.out.println("线程开始运行.");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

运行结果:
    线程开始运行.
    java.lang.InterruptedException: sleep interrupted
	at java.lang.Thread.sleep(Native Method)
	at thread.Inter.run(InterruptTest.java:19)

 抛出了InterruptedException.

join()与yield()

join的作用是插入当前线程,等调用join()的线程运行完毕之后当前线程才能继续运行.

public final void join() throws InterruptedException {
   join(0);
}

public final synchronized void join(long millis)
    throws InterruptedException {
        long base = System.currentTimeMillis(); //先获取当前系统时间
        long now = 0;  //局部变量now.

        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative"); //小于0非法,抛出非法参数异常.
        }

        if (millis == 0) { //传入的参数为0
            while (isAlive()) { //线程还活着的时候
                wait(0); //调用wait(long timeout),参数0,等同于一直wait().
            }
        } else {
            while (isAlive()) {
                long delay = millis - now; 
                //第一次时 时间等于传入的参数-0,之后等于{传入的时间-(最开始的时间-上次循环结束获取的时间)}.
                if (delay <= 0) {
                    break;  //小于0就退出循环.
                }
                wait(delay); //wait(long timeout)传入delay. 
                now = System.currentTimeMillis() - base; 
                //系统当前时间毫秒数减去最开始获取的,赋值给局部变量now,进入循环.
            }
        }
    }

    public final synchronized void join(long millis, int nanos)
    throws InterruptedException {

        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative"); //等待时间非法.
        }

        if (nanos < 0 || nanos > 999999) {
            throw new IllegalArgumentException(
                                "nanosecond timeout value out of range"); //纳秒数值范围
        }

        if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
            millis++;
        }

        join(millis); //调用join(long millis)
    }

可以看到底层调用的是Object的wait(). 

来看看下面的代码:

public class ThreadTest extends Thread{
    public static void main(String[] args) throws InterruptedException{
        int number = 0;
        T t1 = new T(1);
        T t2 = new T(2);
        Thread thread1 = new Thread(t1);
        Thread thread2 = new Thread(t2);
        thread1.start();
        thread2.start();

        for (; number < 5; number++) {
            System.out.println("main:" + number);
        }
    }
}

class T implements Runnable {
    private int number;
    T(int number){this.number = number;}
    @Override
    public void run() {
        int times = 0;
        for (; times < 5; times++) {
            System.out.println(number + ":" + times);
        }
    }
}

其中一次运行结果: 

main:0  ←
main:1  ←
main:2  ←
main:3  ←
main:4  ←
2:0
2:1
2:2
2:3
2:4
1:0
1:1
1:2
1:3
1:4

那么怎么让thread1与thread2先执行呢,此时就要对thread1与thread2调用join(): 

        ......
        thread1.start();
        thread2.start();
        thread1.join();
        thread2.join();
        ......

之后无论怎么运行,main线程的输出都在最后:

1:0
1:1
1:2
1:3
1:4
2:0
2:1
2:2
2:3
2:4
main:0  ←
main:1  ←
main:2  ←
main:3  ←
main:4  ←

其还有传入参数的方法,用来控制时间. 

 yield()就是表示当前线程愿意让出自己的时间片段,但是不保证一定不会调度到这个线程,是个静态本地方法:

    public static native void yield();

Thread.sleep()与Object.wait()

当前线程休眠,但是不释放锁.计时结束之后继续运行,是一个静态本地方法:

    public static native void sleep(long millis) throws InterruptedException;

下面的代码中,thread1是一个计时线程,但是被设置为守护线程,意味着在main()结束sleep后,它就会退出,完成计时:

public class ThreadTest extends Thread{
    public static void main(String[] args) throws InterruptedException{
        T t1 = new T();
        Thread thread1 = new Thread(t1);
        thread1.setDaemon(true); //设置为守护线程
        thread1.start();
        Thread.sleep(5000); //main()"睡眠"5000毫秒.
    }
}

class T implements Runnable {
    int seconds = 0;
    @Override
    public void run() {
        for(;;){ //死循环
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            seconds++;
            System.out.println("main()已经sleep" + seconds + "秒.");
        }
    }
}


运行结果:
    main()已经sleep1秒.
    main()已经sleep2秒.
    main()已经sleep3秒.
    main()已经sleep4秒.
    main()已经sleep5秒.

    Process finished with exit code 0

 对正在sleep中的线程调用interrupt()会抛出InterruptedException.

而wait()同样是让线程暂停运行,区别在于wait()之后会释放锁.

其他方法

long getId() 
获取线程ID.
String getName() 
获取线程名称.
int getPriority() 
获取线程优先级.
Thread.State getState() 
获取线程当前状态.
ThreadGroup getThreadGroup() 
获取所在线程组.
  

方法测试:

  public static void main(String[] args) throws InterruptedException{
        T t1 = new T();
        Thread thread1 = new Thread(t1);
        thread1.setPriority(Thread.MAX_PRIORITY); //thread1设置为最高优先级.
        thread1.start();
        System.out.println("thread1的线程ID:" + thread1.getId());
        System.out.println("main线程的线程ID:" + currentThread().getId());
        System.out.println("thread1的名称:" + thread1.getName());
        System.out.println("main线程的名称:" + currentThread().getName());
        System.out.println("thread1的优先级:" + thread1.getPriority());
        System.out.println("main线程的优先级:" + currentThread().getPriority());
        System.out.println("thread1的状态:" + thread1.getState());
        System.out.println("main线程的状态:" + currentThread().getState());
        System.out.println("thread1所在线程组:" + thread1.getThreadGroup());
        System.out.println("main线程所在线程组:" + currentThread().getThreadGroup());
    }

运行结果:

thread1的线程ID:11
main线程的线程ID:1
thread1的名称:Thread-0
main线程的名称:main
thread1的优先级:10
main线程的优先级:5
thread1的状态:RUNNABLE
main线程的状态:RUNNABLE
thread1所在线程组:java.lang.ThreadGroup[name=main,maxpri=10]
main线程所在线程组:java.lang.ThreadGroup[name=main,maxpri=10]
main()已经sleep1秒.
main()已经sleep2秒.
....