Java 多线程四之常用函数

sleep(long millis)

在指定的毫秒数内让当前正在执行的线程休眠(暂停执行)

例子

SleepThread.java

package cn.zdfy.thread.funsThread;

public class SleepThread implements Runnable {
    private String name;
    private int mIndex = 0;
    private int count;
    public int getmIndex() {
        return mIndex;
    }
    public void setmIndex(int mIndex) {
        this.mIndex = mIndex;
    }
    public SleepThread(String name, int count) {
        this.name = name;
        this.count = count;
    }
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "                 ====线程运行开始!");
        for (int i = 0; i < count; i++) {
            mIndex = i;
            System.out.println("子线程" + name + "运行 : " + i);
        }
        System.out.println(Thread.currentThread().getName() + "                 ====线程运行结束!");
    }
}

测试代码

package cn.zdfy.thread.funsThread;

public class SleepThreadTest {
    public static void main(String[] args) {
        System.out.println(Thread.currentThread().getName() + " 线程 ==== 执行 start");
        SleepThread sa = new SleepThread("A", 10);
        Thread ta = new Thread(sa);
        try {
            System.out.println(Thread.currentThread().getName() + " 线程 睡眠 1s        前");
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName() + " 线程 睡眠 1s        后");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(Thread.currentThread().getName() + " 线程 ==== 执行 end");
    }
}

效果

main 线程 ==== 执行 start
main 线程 睡眠 1s        前
main 线程 睡眠 1s        后
main 线程 ==== 执行 end

join()

join是Thread类的一个方法,启动线程后直接调用,即join()的作用是:“等待该线程终止”,这里需要理解的就是该线程是指的主线程等待子线程的终止。也就是在子线程调用了join()方法后面的代码,只有等到子线程结束了才能执行。
在很多情况下,主线程生成并起动了子线程,如果子线程里要进行大量的耗时的运算,主线程往往将于子线程之前结束,但是如果主线程处理完其他的事务后,需要用到子线程的处理结果,也就是主线程需要等待子线程执行完成之后再结束,这个时候就要用到join()方法了。

例子

JoinThread.java

package cn.zdfy.thread.funsThread;

/**
 * @author zhangpeng
 *
 */
public class JoinThread implements Runnable {
    private String name;
    private int mIndex =0;
    private int count;

    public int getmIndex() {
        return mIndex;
    }

    public void setmIndex(int mIndex) {
        this.mIndex = mIndex;
    }

    public JoinThread(String name, int count) {
        super();
        this.name = name;
        this.count = count;
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "====线程运行开始!");
        for (int i = 0; i < count; i++) {
            mIndex=i;
            System.out.println("子线程" + name + "运行 : " + i);
            try {
                Thread.sleep((int) Math.random() * 10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(Thread.currentThread().getName() + "====线程运行结束!");
    }

}

测试代码

package cn.zdfy.thread.funsThread;

public class JoinThreadTest {
    public static void main(String[] args) {
        System.out.println(Thread.currentThread().getName() + "主线程运行开始!");
        JoinThread thread1 = new JoinThread("A", 10);
        JoinThread thread2 = new JoinThread("B", 10);
        Thread tA = new Thread(thread1);
        Thread tB = new Thread(thread2);
        tA.start();
        tB.start();
        try {
            tA.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        try {
            tB.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "主线程运行结束!");
    }
}

加了join

main主线程运行开始!
Thread-1====线程运行开始!
Thread-0====线程运行开始!
子线程A运行 : 0
子线程B运行 : 0
子线程B运行 : 1
子线程A运行 : 1
子线程B运行 : 2
子线程A运行 : 2
子线程B运行 : 3
子线程A运行 : 3
子线程B运行 : 4
子线程A运行 : 4
子线程B运行 : 5
子线程A运行 : 5
子线程B运行 : 6
子线程A运行 : 6
子线程B运行 : 7
子线程A运行 : 7
子线程B运行 : 8
子线程A运行 : 8
子线程B运行 : 9
子线程A运行 : 9
Thread-1====线程运行结束!
Thread-0====线程运行结束!
main主线程运行结束!

不加join (注释掉代码)

main主线程运行开始!
main主线程运行结束!
Thread-0====线程运行开始!
Thread-1====线程运行开始!
子线程A运行 : 0
子线程B运行 : 0
子线程A运行 : 1
子线程B运行 : 1
子线程A运行 : 2
子线程B运行 : 2
子线程B运行 : 3
子线程A运行 : 3
子线程A运行 : 4
子线程B运行 : 4
子线程A运行 : 5
子线程B运行 : 5
子线程A运行 : 6
子线程B运行 : 6
子线程A运行 : 7
子线程B运行 : 7
子线程B运行 : 8
子线程A运行 : 8
子线程B运行 : 9
子线程A运行 : 9
Thread-1====线程运行结束!
Thread-0====线程运行结束!

总结

加了join会主线程等待该线程结束

yield()

Thread.yield()方法作用是:暂停当前正在执行的线程对象,并执行其他线程。
yield()应该做的是让当前运行线程回到可运行状态,以允许具有相同优先级的其他线程获得运行机会。因此,使用yield()的目的是让相同优先级的线程之间能适当的轮转执行。但是,实际中无法保证yield()达到让步目的,因为让步的线程还有可能被线程调度程序再次选中。

例子

YieldThread.java

package cn.zdfy.thread.funsThread;
public class YieldThread extends Thread {
    public YieldThread(String name) {
        super(name);
    }

    @Override
    public void run() {
        super.run();
        for (int i = 1; i <= 50; i++) {
            System.out.println("" + this.getName() + "=======" + i);
            if (i == 10 || i==20 || i==30) {
                System.out.println(this.getName() + "线程开始退让 ================ 让 cpu 重新分配机会");
                this.yield();
            }
        }
    }
}

测试代码

package cn.zdfy.thread.funsThread;
public class YieldThreadTest {
    public static void main(String[] args) {
        YieldThread ya = new YieldThread("A");
        YieldThread yb = new YieldThread("B");
        ya.start();
        yb.start();
    }
}

效果

A=======1
B=======1
A=======2
B=======2
B=======3
B=======4
A=======3
B=======5
A=======4
B=======6
B=======7
B=======8
B=======9
B=======10
B线程开始退让 ================cpu 重新分配机会
A=======5
A=======6
A=======7
A=======8
A=======9
A=======10
A线程开始退让 ================cpu 重新分配机会
B=======11
A=======11
A=======12
A=======13
A=======14
A=======15
A=======16
A=======17
A=======18
A=======19
A=======20
A线程开始退让 ================cpu 重新分配机会
B=======12
B=======13
B=======14
B=======15
B=======16
B=======17
A=======21
B=======18
A=======22
B=======19
B=======20
B线程开始退让 ================cpu 重新分配机会
A=======23
A=======24
A=======25
A=======26
B=======21
A=======27
B=======22
A=======28
A=======29
A=======30
A线程开始退让 ================cpu 重新分配机会
B=======23
B=======24
B=======25
B=======26
B=======27
B=======28
B=======29
B=======30
B线程开始退让 ================cpu 重新分配机会
A=======31
A=======32
A=======33
A=======34
A=======35
A=======36
A=======37
A=======38
A=======39
A=======40
A=======41
A=======42
A=======43
A=======44
A=======45
A=======46
A=======47
A=======48
A=======49
A=======50
B=======31
B=======32
B=======33
B=======34
B=======35
B=======36
B=======37
B=======38
B=======39
B=======40
B=======41
B=======42
B=======43
B=======44
B=======45
B=======46
B=======47
B=======48
B=======49
B=======50

结论:yield()从未导致线程转到等待/睡眠/阻塞状态。在大多数情况下,yield()将导致线程从运行状态转到可运行状态,但有可能没有效果,说白了只是重新回到CPU重新分配的时机

setPriority():

更改线程的优先级。
MIN_PRIORITY = 1
NORM_PRIORITY = 5
MAX_PRIORITY = 10

例子

PriorityThread .java

package cn.zdfy.thread.funsThread;
public class PriorityThread extends Thread {
    public PriorityThread(String name) {
        super(name);
    }
    @Override
    public void run() {
        super.run();
        for (int i = 1; i <= 10; i++) {
            System.out.println(this.getName() + "=======" + i);
        }
    }
}

测试代码

package cn.zdfy.thread.funsThread;

public class PriorityThreadTest {
    public static void main(String[] args) {
        PriorityThread pa = new PriorityThread("A");
        PriorityThread pb = new PriorityThread("B");
        pa.setPriority(Thread.MAX_PRIORITY);
        pb.setPriority(Thread.MIN_PRIORITY);
        pa.start();
        pb.start();
    }
}

效果

A=======1
A=======2
A=======3
A=======4
A=======5
A=======6
A=======7
A=======8
A=======9
A=======10
B=======1
B=======2
B=======3
B=======4
B=======5
B=======6
B=======7
B=======8
B=======9
B=======10

总结: 优先级高的优先执行

wait()

Obj.wait(),与Obj.notify()必须要与synchronized(Obj)一起使用,也就是wait,与notify是针对已经获取了Obj锁进行操作,从语法角度来说就是Obj.wait(),Obj.notify必须在synchronized(Obj){…}语句块内。从功能上来说wait就是说线程在获取对象锁后,主动释放对象锁,同时本线程休眠。直到有其它线程调用对象的notify()唤醒该线程,才能继续获取对象锁,并继续执行。相应的notify()就是对对象锁的唤醒操作。但有一点需要注意的是notify()调用后,并不是马上就释放对象锁的,而是在相应的synchronized(){}语句块执行结束,自动释放锁后,JVM会在wait()对象锁的线程中随机选取一线程,赋予其对象锁,唤醒线程,继续执行。这样就提供了在线程间同步、唤醒的操作。Thread.sleep()与Object.wait()二者都可以暂停当前线程,释放CPU控制权,主要的区别在于Object.wait()在释放CPU同时,释放了对象锁的控制。

单单在概念上理解清楚了还不够,需要在实际的例子中进行测试才能更好的理解。对Object.wait(),Object.notify()的应用最经典的例子,应该是三线程打印ABC的问题了吧,这是一道比较经典的面试题,题目要求如下:
建立三个线程,A线程打印10次A,B线程打印10次B,C线程打印10次C,要求线程同时运行,交替打印10次ABC。这个问题用Object的wait(),notify()就可以很方便的解决。

例子

WaitThread.java

package cn.zdfy.thread.funsThread;
public class WaitThread implements Runnable {
    private String name;
    private Object prevObj;
    private Object selfObj;
    public WaitThread(String name, Object prevObj, Object selfObj) {
        this.name = name;
        this.prevObj = prevObj;
        this.selfObj = selfObj;
    }
    @Override
    public void run() {
        int count = 10;
        while (count > 0) {
            synchronized (prevObj) {
                synchronized (selfObj) {
                    System.out.print(name);
                    count--;
                    selfObj.notify(); // 唤醒
                }
                try {
                    prevObj.wait(); // 释放对象锁
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

测试代码
WaitThreadTest.java

package cn.zdfy.thread.funsThread;

public class WaitThreadTest {
    public static void main(String[] args) throws InterruptedException {
        Object a = new Object();
        Object b = new Object();
        Object c = new Object();
        WaitThread wa = new WaitThread("A", c, a);
        WaitThread wb = new WaitThread("B", a, b);
        WaitThread wc = new WaitThread("C", b, c);
        new Thread(wa).start();
        Thread.sleep(100); // 确保按顺序A、B、C执行
        new Thread(wb).start();
        Thread.sleep(100); 
        new Thread(wc).start();
        Thread.sleep(100); 
    }
}

效果

ABCABCABCABCABCABCABCABCABCABC

猜你喜欢

转载自blog.csdn.net/qg_zhang/article/details/79629541
今日推荐