Java Thread Programming 1.6 - Thread Prioritization

 
 
System Thread Priorities—JDK 1.2
Priority
Thread Name
5
main
8
Finalizer
10
Reference Handler
5
Signal dispatcher
5
AWT-Windows
6
AWT-EventQueue-0
5
SunToolkit.PostEventQueue-0
4
Screen Updater
 
A notable change in JDK 1.2 is that the priority of the Finalizer thread was increased from 1 to 8 to help ensure that the garbage collector gets more of a chance to run and free up memory.
 
Jdk1.2中Finalizer线程的优先级从1升高到8,确保垃圾收集器能及时回收资源释放内存
 
When assigning priorities to your threads, you should consider the relative priorities of the system threads to be sure your threads don’t overwhelm their operations. By default, when a new Thread is constructed, it runs at the same priority as the thread that constructed it. Most new threads are constructed directly or indirectly by the main thread and will therefore run at a priority of 5. This works well under many scenarios, but there are times when you will want to raise or lower a thread’s priority.
 
子线程的优先级和父线程的优先级相同,大部分线程从main线程创建,所以优先级为5
 
There are three public static final int member variables of Thread that indicate the range of priority values that can be passed to setPriority().
Thread.MAX_PRIORITY
Thread.MIN_PRIORITY
Thread.NORM_PRIORITY
 
Thread类中有三个静态优先级变量
Thread.MAX_PRIORITY,最高优先级,通常为10
Thread.MIN_PRIORITY,最低优先级,通常为1
Thread.NORM_PRIORITY,一般优先级,通常为5
 
getPriority()
 
The getPriority() method of Thread returns an int representing the current priority of the thread. Generally, a thread’s priority does not change over its lifetime, but it can.
 
getPriority()返回线程的当前优先级,通常线程的优先级在其生命周期中不会变,但可以变
 
setPriority()
 
The setPriority() method of Thread takes an int as a parameter indicating the new priority for the thread. The setPriority() method can be invoked either before the thread is started or once it is running. Some VMs might allow you to change the priority of the system threads, but this is not recommended—even if it is permitted.
 
setPriority()设置线程新的优先级,可以在线程开始前调用,也可以在线程运行中调用,有些虚拟机允许改变系统线程的优先级,但我们不推荐这么做
 
Calls to setPriority can throw a SecurityException if the calling thread is not permitted to make the priority change. This will happen only if there is a SecurityManager installed and it rejects the change request. By default, applications do not have a SecurityManager.
 
如果不允许线程优先级改变,调用setPriority()方法时会抛出SecurityException异常,当安装了SecurityManager时,可能会出现这种情况
 
An IllegalArgumentException will be thrown if the specified priority is greater than Thread.MAX_PRIORITY or less than Thread.MIN_PRIORITY.allowed for the thread group. For example, in this code fragment
 
Thread t = //...
ThreadGroup tg = t.getThreadGroup();
int groupMax = tg.getMaxPriority();
 
the maximum value for the thread priority of thread t is groupMax. Usually, this is the same as Thread.MAX_PRIORITY. When groupMax is less than Thread.MAX_PRIORITY, calls to setPriority() still work, but will silently reduce the value passed to groupMax. If groupMax is 6 and setPriority(9) is called, the code will run as if setPriority(6) was called instead. See Chapter 10, “Thread Groups,” for more on ThreadGroup.
 
如果将线程优先级设置在线程组的Thread.MAX_PRIORITY,和Thread.MIN_PRIORITY之外,会抛出IllegalArgumentException异常。线程组允许的最大优先级和Thread.MAXPRIORITY可能会不一致,如果线程组最大优先级为6,而将线程优先级设置为9,那么代码执行的结果和setPriority(6)一样。
 
 
Thread States
 
State
Blocked
Interrupted
Discription
Running
 
 
Current running on the processor
Ready to run
 
 
Waiting for the processor
Sleeping
Will move to “ready to run” state
after a certain amount of time has eclipsed or after being interrupted
Waiting
Will move to “ready to run” state
after being notice, after timeout or after being interrupted
Blocked on I/O
 
Will move to “ready to run” after I/O
Condition changes(for example,a byte of date is read)
Blocked on sync
 
Will move to “ready to run” when lock is acquired(passes synchronized statement)
 
Threads can be blocked in one of four states. When a thread executes Thread.sleep(), it blocks until the specified number of milliseconds passes or until it is interrupted by another thread. When a thread encounters a wait() statement (see Chapter 8, “Inter-thread Communication,” for more on the wait/notify mechanism), it blocks until it is notified, interrupted, or the specified number of milliseconds elapses (if a timeout was specified).
 
There are many ways a thread can block waiting on different I/O methods. One common way is the read() method of InputStream. This method blocks until a byte of data is read from the stream. It can block indefinitely, and no timeout can be specified.
 
A thread can also block waiting to acquire exclusive access to an object’s lock. The synchronized statement and synchronized method modifier (see Chapter 7, “Concurrent Access to Objects and Variables,” for more on synchronization) are used to control concurrent access by more than one thread to a section of code. A thread will block on synchronized until it gets the specified lock. It can block indefinitely, and no timeout can be specified.
 
有四种方式线程会被阻塞:
1、调用Thread.sleep(),时间完成、被其他线程打断时改变状态
2、wait/notify时线程遇到wait()时,当被notified,被别的线程打断,或者特定时间结束时改变状态
3、I/O阻塞
4、锁阻塞,同步锁时,线程得到此锁时改变状态
 
Notice that not all blocked states are interruptible. When a thread is blocked waiting to read a byte of data from an InputStream, it will not respond to interrupts (see Chapter 15, “Breaking Out of a Blocked I/O State,” for some techniques for dealing with this). When a thread is blocked waiting to get the lock required by a synchronized statement, it also will not respond to interrupt requests (see Chapter 17, “BooleanLock Utility,” for a technique that deals with long waits for locks).
 
不是所有的阻塞状态都可以被打断的,I/O阻塞和锁阻塞是不能被中断的
 
Thread.yield()
 
To help ensure that other threads in the VM get a turn to run on the processor, a thread can voluntarily give up its turn early. If a thread invokes the static method Thread.yield(), the thread scheduler will swap it off the processor and allow another thread to run. It is likely (but not guaranteed) that only threads having a priority equal to or greater than the one that yielded control will be considered by the thread scheduler.
 
Thread.yield():线程自愿让出cpu控制权
 
A thread implicitly yields the processor when it goes to sleep or otherwise blocks. The Thread.yield() method allows a thread to specify other times that are convenient for it to pause to allow other threads access to the processor. If you have a thread that frequently blocks on its own, there is no need to make Thread.yield() calls. But, if you have a thread that is performing a long non-blocking calculation, an occasional call to Thread.yield() can help split up the processor resources among the other threads. Be careful not to overuse Thread.yield() as some system overhead is incurred to perform a context switch between threads. As a rough guideline, try to avoid calling Thread.yield() more than five times per second.
 
当线程阻塞时(四种原因),线程隐式自行yield。如果线程本身经常阻塞,就没有必要显式调用yield,如果线程执行一个长时间不阻塞的大运算,调用一下能够给其他进程平分一下处理器资源。注意:不要频繁调用,因为yield时系统做上下文切换,很是耗费系统资源和时间,避免疫秒内调用五次以上的yield。
 
实例: PriorityYield.java
/*
 * Created on 2005-7-8
 *
 * Java Thread Programming - Paul Hyde
 * Copyright ? 1999 Sams Publishing
 * Jonathan Q. Bo 学习笔记
 *
 */
package org.tju.msnrl.jonathan.thread.chapter1;
 
/**
 * @author Jonathan Q. Bo from TJU MSNRL
 *
 * Email:jonathan.q.bo@gmail.com
 * Blog:blog.csdn.net/jonathan_q_bo
 *      blog.yesky.net/jonathanundersun
 *
 * Enjoy Life with Sun!
 *
 */
public class PriorityYield {
    private volatile int counter;
    private Thread innerThread;
    private volatile boolean stopRequest;
    private boolean yield;
   
    public PriorityYield(String name,int priority,boolean yield){
        this.yield = yield;
        this.counter = 0;
        this.stopRequest = false;
       
        Runnable r = new Runnable(){
            public void run(){
                try{
                    runwork();
                }catch(Exception e){
                    System.out.println(e.getMessage());
                }
            }
        };
       
        innerThread = new Thread(r,name);
        innerThread.setPriority(priority);
    }
   
    /** 线程主体 */
    public void runwork(){
        Thread.yield();
        while(!this.stopRequest){
            if(this.yield){
                Thread.yield();
            }
            counter++;
           
            double x = 0;
            for(int i = 0; i < 1000; i++)//让线程处于活动状态,而不是sleep
                x = Math.PI*i/Math.E;
        }
    }
 
    /** 开始线程 */
    public void startThread(){
        this.innerThread.start();
    }
   
    /** 结束线程 */
    public void stopThread(){
        this.stopRequest = true;
    }
   
    public int getCounter(){
        return this.counter;
    }
   
    /** 返回线程优先级和线程名 */
    public String getPriorityandName(){
        return "Thread:" + innerThread.getName() + "/Priority:" + innerThread.getPriority();
    }
   
    public static void runMain(boolean yield){
        /*定义三个线程*/
        PriorityYield[] pys = new PriorityYield[3];
        pys[0] = new PriorityYield("PY0",3,yield);
        pys[1] = new PriorityYield("PY1",6,yield);
        pys[2] = new PriorityYield("PY2",6,yield);
       
        try{
            Thread.sleep(1000);
        }catch(InterruptedException e){}
       
        /*启动三线程*/
        for(int i = 0 ; i < pys.length; i++){
            pys[i].startThread();
        }
       
        long startTime = System.currentTimeMillis();
       
        /*让线程运行一段时间*/
        try{
            Thread.sleep(10000);
        }catch(InterruptedException e){}
       
        /*停止线程运行*/
        for(int i = 0; i < pys.length; i++){
            pys[i].stopThread();
        }
       
        long stopTime = System.currentTimeMillis();
       
        /*等线程完全停止运行*/
        try{
            Thread.sleep(1000);
        }catch(InterruptedException e){}
       
        /*获得三线程总计数*/
        int totalCounter = 0;
        for(int i = 0; i < pys.length; i++){
            totalCounter += pys[i].getCounter();
        }
       
        /*输出统计结果*/
        System.out.println("totalcount=" + totalCounter + "  counter/ms=" + totalCounter/(stopTime - startTime));
        for(int i = 0; i < pys.length; i++){
            System.out.println(pys[i].getPriorityandName() + ", count=" + pys[i].counter + " ," + pys[i].counter*100/totalCounter + "%");
        }
    }
   
    public static void main(String[] args) {
        Runnable r =new Runnable(){
            public void run(){
                System.out.println("run without yield");
                runMain(false);//不使用yield
                System.out.println();
                System.out.println("run with yield");
                runMain(true);//使用yield
            }
        };
        Thread t = new Thread(r,"PriorityYield");
        t.setPriority(Thread.MAX_PRIORITY - 1);
        t.start();
    }
}
 
 
输出结果:
 
run without yield
totalcount=454665  counter/ms=45
Thread:PY0/Priority:3, count=0 ,0%
Thread:PY1/Priority:6, count=235049 ,51%
Thread:PY2/Priority:6, count=219616 ,48%
 
run with yield
totalcount=401611  counter/ms=40
Thread:PY0/Priority:3, count=0 ,0%
Thread:PY1/Priority:6, count=200805 ,49%
Thread:PY2/Priority:6, count=200806 ,50%
 
通过调用yield的对比实验很明显看出
1、  优先级高的获得更多的处理器周期
2、  同一优先级的线程又相同的运行机会
3、  调用yield不会增加性能,而是降低了cpu总周期
 
Also note that without yielding, the count/ms was about 76 (line 3), and when yielding was done, it was cut down to about 25 (line 10). This shows that the yielding caused a lot of context switches that brought with them some significant overhead. In this example, the excessive yielding wasted processor resources.
 
频繁的yield浪费处理器资源
 
When assigning priorities to the threads in your application, use the higher priorities only for threads that block frequently (sleeping, waiting, I/O). CPU-intensive calculations should be done with a medium- to low-priority thread to ensure that the processor is not hogged. Avoid setting a priority to Thread.MAX_PRIORITY unless the thread spends nearly all of its time blocked or is very short-lived.
 
给经常阻塞的线程高的优先级,给密集运算的线程中低优先级保证处理器不会被独占,避免设置优先级为Thread.MAX_PRIORITY,除非线程的生命周期特别短或者整个生命周期中基本都处于阻塞状态
 
Thread scheduling varies from VM to VM and from operating system to operating system. Because of these differences, prioritization should only be used to try to improve responsiveness and efficiency, and should not be relied upon for program correctness.
 
不同的虚拟机不同的操作系统有不同的线程调用机制,由于这些不同,线程优先级只是用来提高响应和效率的一种手段,不能作为程序正确性的依赖。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值