天天看点

Java多线程——线程操作(方法)

Java多线程中我们有一些常用的操作线程的方法,如start(),sleep(),join(),yield(),wait(),notify()和interrupt()等方法。就是这些方法我们才能启动线程使线程完成我们想要完成的任务。我写过一篇创建线程的博客,其中就介绍了线程的三种状态:就绪状态,运行状态和阻塞状态。而以上一些方法的调用就是线程状态变化的原因之一。

1.有关线程名称的方法

我们首先来看看Thread类的一个构造方法:

public Thread(Runnable target, String name)
           

这个构造方法可以传入一个Runnable类型对象和String对象。我们知道传入的Runnable类型的对象实际上就是我们赋予这个线程的任务,而这个String对象实际上就是我们为这个线程赋予的名称。

我们来试一试:

public class NameTest1 {

    public static void main(String[] args) {

        Thread thread1 = new Thread(new Runnable() {
            public void run() {
                System.out.println("这是线程");
            }
        },"Thread-user1");
        
    }

}
           

那么我们这个线程的名称到底是不是我们所赋的名称呢?我们就要用到查看线程的方法了。

public final String getName()
           

这个方法会返回调用这个方法的线程的线程名称。

我们使用这个方法来查看上面的的代码是否赋名成功:

public class NameTest1 {

    public static void main(String[] args) {

        Thread thread1 = new Thread(new Runnable() {
            public void run() {
                System.out.println("这是线程");
            }
        },"Thread-user1");

        System.out.println("thread1线程的名称为:" + thread1.getName());

    }

}
           

结果:

Java多线程——线程操作(方法)

可以看到,我们的线程名称与我们所赋的名称是相同的。

那么如果我们想要更改一个线程的名称怎么办呢?就要用到这个方法:

public final synchronized void setName(String name)
           

这个方法会修改调用这个方法的线程的线程名称。

我们来试一试:

public class NameTest1 {

    public static void main(String[] args) {

        Thread thread1 = new Thread(new Runnable() {
            public void run() {
                System.out.println("这是线程");
            }
        },"Thread-user1");

        System.out.println("thread1线程的名称为:" + thread1.getName());

        thread1.setName("Thread-newName");

        System.out.println("thread1线程的名称为:" + thread1.getName());

    }

}
           

结果:

Java多线程——线程操作(方法)

2.sleep()方法

public static native void sleep(long millis)
           

这个方法Thread类的静态方法,需要传入一个long型数据(millis表示单位为毫秒)。这个方法会使调用它的线程(调用这个方法所在的线程)休眠,休眠时间为传入的参数大小乘以1毫秒。

!!!注意:线程使用这个方法进入休眠时会释放CPU资源,但不会释放锁。

我们来使用一下这个方法:

public class SleepTest {

    public static void main(String[] args) throws InterruptedException {

        Runnable runnable = new Runnable() {

            private volatile int i = 0;

            public void run() {
                for(;;){
                    Thread thread = Thread.currentThread();
                    synchronized (this){
                        i++;
                        if(i<6){
                            System.out.println(thread.getName() + "线程。。。" + i);
                        }else {
                            while(true){
                                try {
                                    Thread.sleep(1000);
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                }
                            }
                        }
                    }
                }
            }
        };

        Thread thread1 = new Thread(runnable,"Thread-test1");
        Thread thread2 = new Thread(runnable,"Thread-test2");
        thread1.start();
        thread2.start();

    }

}
           

结果如图:

Java多线程——线程操作(方法)

可以看到,此时程序无法结束,这是因为线程1休眠无法终止。而线程1休眠后,线程2却仍然不能执行被同步的代码块。

2.yield()方法

public static native void yield()
           

这个方法是Thread类的静态方法,这个方法会暂停调用这个方法的线程(调用这个方法所在的线程),释放CPU资源,但不会释放锁。看起来这个方法和Sleep有些相似,但是它们也有区别:1.这个方法暂停时间是没法控制的;2.暂停结束后直接进入就绪态,不会造成阻塞;3.线程因这个方法释放的CPU资源只能被与线程同优先级的线程获得。

不使用这个方法:

public class YieldTest {

    public static void main(String[] args) {

        Runnable runnable = new Runnable() {
            public void run() {
                for(int i=0; i<5; i++){
//                    Thread.yield();
                    System.out.println(Thread.currentThread().getName() + "线程打印的: i = " + i);
                }
            }
        };

        new Thread(runnable,"Thread-test1").start();
        new Thread(runnable,"Thread-test2").start();
        new Thread(runnable,"Thread-test3").start();

    }

}
           

结果:

Java多线程——线程操作(方法)

去掉注释后,使用了yield()方法后的结果:

Java多线程——线程操作(方法)

我们可以看到使用了yield()方法后的打印是无规律的。

3.join()方法

public final void join()
           

该方法会使所在线程休眠,直到调用该方法的线程执行完毕之后再开始执行所在线程。

不使用该方法:

public class JoinTest {

    public static void main(String[] args) throws InterruptedException {
        Runnable runnable = new Runnable() {
            public void run() {
                String name = Thread.currentThread().getName();
                synchronized (this){
                    Thread.yield();
                    System.out.println(name + "执行");
                }
            }
        };

        Thread thread1 = new Thread(runnable,"Thread-test1");
        Thread thread2 = new Thread(runnable,"Thread-test2");
        Thread thread3 = new Thread(runnable,"Thread-test3");
        Thread thread4 = new Thread(runnable,"Thread-test4");
        Thread thread5 = new Thread(runnable,"Thread-test5");

        thread1.start();
//        thread1.join();
        thread2.start();
//        thread2.join();
        thread3.start();
//        thread3.join();
        thread4.start();
//        thread4.join();
        thread5.start();
//        thread5.join();
    }

}
           

不使用该方法的结果:

Java多线程——线程操作(方法)

使用该方法的结果:

Java多线程——线程操作(方法)

4.interrupt()方法

public void interrupt()
           

该方法会将线程的中断标志位修改为true。当中断标志位为true后,如果线程未受阻塞,那么就只是中断标志位变为true;若是线程处于阻塞状态,此时受阻线程会抛出一个异常以退出阻塞状态,同时中断标志位变回false。

使用这个方法:

public class InterruptTest {

    public static void main(String[] args) throws InterruptedException {

        Runnable runnable = new Runnable() {
            public void run() {
                while(true){
                    boolean bool = Thread.currentThread().isInterrupted();
                    System.out.println(Thread.currentThread().getName() + "线程是否中断:" + bool);
                    if(bool){
                        System.out.println(Thread.currentThread().getName() + "线程阻塞");
                        return;
                    }
                }
            }
        };

        Thread thread = new Thread(runnable, "Thread-test");
        thread.start();
        Thread.sleep(2);
        thread.interrupt();

    }

}
           

结果:

Java多线程——线程操作(方法)

!!!注意:interrupt()方法只是修改了中断标志位,实际上不会中断线程

请看如下代码:

public class InterruptTest {

    public static void main(String[] args) throws InterruptedException {

        Runnable runnable = new Runnable() {
            public void run() {
                while(true){
                    boolean bool = Thread.currentThread().isInterrupted();
                    System.out.println(Thread.currentThread().getName() + "线程是否中断:" + bool);
//                    if(bool){
//                        System.out.println(Thread.currentThread().getName() + "线程阻塞");
//                        return;
//                    }
                }
            }
        };

        Thread thread = new Thread(runnable, "Thread-test");
        thread.start();
        Thread.sleep(2);
        thread.interrupt();

    }

}
           

结果:

Java多线程——线程操作(方法)

可以看到此时中断标志位为true,但是线程却并没有中断。

5.wait()方法和notify()方法

这两个方法相对于其它方法有一些特殊,而且这两个方法一般都是成对使用,所以我把他们放在一起。

public final void wait()
           

该方法是Object类的成员方法,调用该方法会使线程在wait()方法的代码处停止,线程被置入“预执行队列”中,等待通知或中断,同时线程释放锁。

!!注意:wait()方法必须在同步方法或同步代码块中使用。

public final native void notify()
           

该方法是Object类的成员方法,调用该方法后将会在调用该方法的对象的“预执行队列”中随机挑出一个线程进行通知。该方法一般与wait()方法成对使用。还有notifyAll()方法,则会将调用该方法的对象的“预执行队列”中所以线程进行通知。

!!注意:notify()方法必须在同步方法或同步代码块中使用,而且其与wait()方法成对使用时,锁的对象必须是同一对象。

如下代码:

public class WaitAndNotifyTest {

    public static void main(String[] args) throws InterruptedException {
        Runnable runnable = new Runnable() {
            public void run() {
                for(int i=0; i<10; i++){
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    if(i == 2){
                        System.out.println(Thread.currentThread().getName() + "调用wait方法,开始等待");
                        try {
                            synchronized (this){
                                this.wait();
                            }
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println(Thread.currentThread().getName() + "线程打印:i = " + i);
                }
            }
        };

        Thread thread1 = new Thread(runnable,"Thread-test");
        thread1.start();
        Thread.sleep(5000);
        synchronized (runnable){
            System.out.println("通知" + thread1.getName() + "线程");
            runnable.notify();
        }
    }

}
           

结果:

Java多线程——线程操作(方法)

我的所有演示代码都上传在github,链接:https://github.com/nodonotnodo/JavaSE-csdn