目录

  • Java开发入门
    • ● Java 概述
    • ● JDK的使用
    • ● 系统环境变量
    • ● 第一个Java程序
    • ● Java的运行机制
    • ● 教学设计
    • ● 课程讲义
    • ● 案例学习
    • ● 课后题答案
  • Java 编程基础
    • ● Java的基本语法
      • ● Java代码基本格式
      • ● Java中的注释
      • ● Java中的关键字
      • ● Java中的标识符
    • ● Java中的变量与常量
      • ● 变量的定义
      • ● 变量的数据类型
        • ● 案例导学
      • ● 变量的类型转换
        • ● 案例导学-自动类型转换
        • ● 案例导学-强制类型转换
      • ● 变量的作用域
        • ● 案例导学-作用域
      • ● Java中的常量
    • ● Java中的运算符
      • ● 案例导学-算术运算符
      • ● 案例导学-赋值运算符
      • ● 案例导学-比较运算符
      • ● 案例导学-逻辑运算符
      • ● 案例导学-位运算符
      • ● 案例导学-运算符的优先级
    • ● 选择结构语句
      • ● 案例导学-if条件语句
      • ● 案例导学-switch条件语句
    • ● 循环结构语句
      • ● 案例导学-while循环语句
      • ● 案例导学-for循环语句
      • ● 案例导学-循环嵌套
      • ● 案例导学-break语句
      • ● 案例导学-continue语句
    • ● 数组
      • ● 案例导学-一维数组的定义
      • ● 案例导学-数组最值
      • ● 案例导学-数组排序
    • ● 教学设计
    • ● 课程讲义
    • ● 课后题答案
  • 面向对象(上)
    • ● 面向对象概述
    • ● Java中的类与对象
      • ● 案例导学-类与对象
    • ● 类的封装
    • ● 案例导学-类的封装
    • ● 方法的重载和递归
    • ● 构造方法
      • ● 案例导学-构造方法与重载
    • ● this关键字
      • ● 案例导学-this
    • ● static关键字
      • ● 案例导学-静态变量
      • ● 案例导学-静态方法
      • ● 案例导学-静态代码块
    • ● 教学设计
    • ● 课程讲义
    • ● 章节测试
    • ● 课后题答案
  • 面向对象(下)
    • ● 类的继承
      • ● 案例导学-类的继承
      • ● 案例导学-方法的重写
      • ● 案例导学-super访问父类成员变量
      • ● 案例导学-super访问父类成员方法
      • ● 案例导学-super访问父类构造方法
    • ● final关键字
    • ● 抽象类和接口
    • ● 多态
    • ● 内部类
    • ● JDK8的Lambda表达式
    • ● 异常
    • ● 垃圾回收
    • ● 教学设计
    • ● 课程讲义
    • ● 章节测试
    • ● 课后习题答案
  • Java中的常用类
    • ● String类和StringBuffer类
    • ● System类与Runtime类
    • ● Math类与Random类
    • ● 包装类
    • ● 日期与时间类
    • ● 格式化类
    • ● 课后题答案
    • ● 课程讲义
  • 集合
    • ● 集和概述
    • ● Collection接口
    • ● List接口
      • ● List接口简介
      • ● ArrayList集合
      • ● LinkList集合
    • ● Collection集合遍历
    • ● Set接口
    • ● Map接口
    • ● 泛型
    • ● 常用工具类
      • ● Collections工具类
      • ● Arrays工具类
    • ● 课后题参考答案
    • ● 课程讲义
  • IO流
    • ● I/O流概述
    • ● 字节流
    • ● 字符流
    • ● File类
    • ● RandomAccessFile
    • ● 对象序列化
    • ● NIO
    • ● NIO.2
    • ● 课后题答案
    • ● 课程讲义
    • ● 章节测试
  • GUI(图形用户接口)
    • ● Swing概述
    • ● Swing顶级容器
    • ● 布局管理器
    • ● 事件处理
    • ● Swing常用组件
    • ● Swing组件的整合使用
    • ● JavaFX图形用户界面工具
    • ● 课程讲义
  • JDBC
    • ● 什么是JDBC
    • ● JDBC常用API
    • ● JDBC编程
    • ● 案例-使用JDBC实现QQ登录
    • ● 课程讲义
  • 多线程
    • ● 线程概述
    • ● 线程的创建
    • ● 线程的生命周期及状态转换
    • ● 线程的调度
    • ● 多线程同步
    • ● 多线程通信
    • ● 教学设计
    • ● 课后题参考答案
    • ● 课程讲义
  • 网络编程
    • ● 网络通信协议
    • ● UDP通信
    • ● TCP通信
    • ● 课程讲义
  • Eclipse开发工具
    • ● Eclipse概述
    • ● Eclipse的安装与启动
    • ● Eclipse进行程序开发
    • ● Eclipse程序调试
    • ● 使用Eclipse导出、导入jar文件
  • ACM大赛题库
    • ● 2027
    • ● 2028
    • ● 2024-2026
    • ● 2012-2023
    • ● 2018-2020
    • ● 2015-2017
    • ● 2012-2014
    • ● 2009-2011
    • ● 2003-2005
    • ● 2000-2002
  • PBL学生风采展示
    • ● 实验一
    • ● 实验二
    • ● 实验三
    • ● 实验四
线程的调度

线程优先级的取值

Java线程的优先级是一个整数,其取值范围是1 (Thread.MIN_PRIORITY ) - 10 (Thread.MAX_PRIORITY )。

Thread源代码里对NORM_PRIORITY (数值为5) 的注释是“线程默认的优先级”。其实不然。默认的优先级是父线程的优先级。

设置优先级

可以通过setPriority方法(final的,不能被子类重载)更改优先级。优先级不能超出1-10的取值范围,否则抛出IllegalArgumentException。另外如果该线程已经属于一个线程组(ThreadGroup),该线程的优先级不能超过该线程组的优先级:

if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {

   throw new IllegalArgumentException();

}

if((g = getThreadGroup()) != null) {

   if (newPriority > g.getMaxPriority()) {

newPriority = g.getMaxPriority();

   }

   setPriority0(priority = newPriority);

        }

    }

线程组的最大优先级

我们可以设定线程组的最大优先级,当创建属于该线程组的线程时该线程的优先级不能超过这个数。

 

线程组最大优先级的设定:

  • 系统线程组的最大优先级默认为Thread.MAX_PRIORITY

  • 创建线程组的时候其最大优先级默认为父线程组(如果未指定父线程组,则其父线程组默认为当前线程所属线程组)的最大优先级

  • 可以通过setMaxPriority更改最大优先级,但无法超过父线程组的最大优先级

setMaxPriority的问题:

  • 该方法只能更改本线程组及其子线程组(递归)的最大优先级。

  • 但不能影响已经创建的直接或间接属于该线程组的线程的优先级,也就是说,即使目前有一个子线程的优先级比新设定的线程组优先级大,也不会更改该子线程的优先级。只有当试图改变子线程的优先级或者创建新的子线程的时候,线程组的最大优先级才起作用。

线程休眠

sleep() 定义在Thread.java中。
    sleep() 的作用是让当前线程休眠,即当前线程会从“运行状态”进入到“休眠(阻塞)状态”。sleep()会指定休眠时间,线程休眠的时间会大于/等于该休眠时间;在线程重新被唤醒时,它会由“阻塞状态”变成“就绪状态”,从而等待cpu的调度执行。

class MyThead implements Runnable

{

public void run()

{

System.out.println("我休息了!");

try

{

Thread.sleep(1000);

}

catch (InterruptedException e)

{

}

System.out.println("一秒后在叫我吧!");

}

}


public class TheadMain

{

public static void main(String[] args)

{

MyThead myThead = new MyThead();

Thread thread = new Thread(myThead);

thread.start();

}

}

sleep()与wait()的比较

我们知道,wait()的作用是让当前线程由“运行状态”进入“等待(阻塞)状态”的同时,也会释放同步锁。而sleep()的作用是也是让当前线程由“运行状态”进入到“休眠(阻塞)状态”。但是,wait()会释放对象的同步锁,而sleep()则不会释放锁。

public class ThreadB extends Thread{

     

     private static Object obj = new Object();

     

     public ThreadB(String name){ 

         super(name); 

     }

     

     public void run(){

         synchronized(obj){

             try {

                 for(int i=0; i <10; i++){ 

                     System.out.printf("%s: %d\n", this.getName(), i); 

                     // i能被4整除时,休眠100毫秒

                     if (i%4 == 0)

                         Thread.sleep(100);

                 }

             } catch (InterruptedException e) {

                 e.printStackTrace();

             }

         }

     }

}

public class SleepLockTest {

     public static void main(String[] args){  

         ThreadB t1 = new ThreadB("t1"); 

         ThreadB t2 = new ThreadB("t2"); 

         t1.start(); 

         t2.start();

     }

}

线程让步yield()方法

yield()方法可以让当前正在执行的线程暂停,但它不会阻塞该线程,它只是将该线程从运行状态转入就绪状态

只是让当前的线程暂停一下,让系统的线程调度器重新调度一次。

很有可能,当某个线程调用了yield()方法暂停之后进入就绪状态,它又马上抢占了CPU的执行权,继续执行。

注意:

实际上,当某个线程调用了yield()方法暂停之后,只有优先级与当前线程相同,或者优先级比当前线程更高的处于就绪状态的线程才会获得执行的机会。

class YieldThread implements Runnable{

    

    public void run() {

        for(int i=0;i<100;i++){

            

            if(i==20){

                //当i==20的时候,使用yield方法使当前线程让步

                Thread.yield();

            }

            System.out.println(Thread.currentThread().getName()+"===="+i);

        }

    };

}


public class Demo03 {

    public static void main(String[] args) {

        YieldThread yt=new YieldThread();

        Thread t1=new Thread(yt,"高级");

        t1.setPriority(Thread.MAX_PRIORITY);  //将t1线程设置成最高优先级

        

        Thread t2=new Thread(yt,"低级");

        t2.setPriority(Thread.MIN_PRIORITY);  //将t2线程设置成最低优先级

        

        t2.start();

        t1.start();

        

    }

}

                    sleep和yield的区别

1.sleep()方法暂停当前线程后,会给其他线程执行机会,线程优先级对此没有影响。

yield()方法会给优先级相同或更高的线程更高的执行机会。 

2.sleep()方法会将线程转入阻塞状态,直到阻塞时间结束,才会转入就绪状态。

yield()方法会将当前线程直接转入就绪状态。

3.sleep()方法声明抛出了InterruptedException异常,所以调用sleep()方法时要么捕捉该异常,要么显示声明抛出该异常。

yield()方法则没有声明抛出任何异常。

4.sleep()方法比yield()方法有更好的移植性,通常不建议使用yield()方法来控制并发线程的执行。

                    设置线程的优先级

Thread了提供了以下两个优先级相关方法:

1.setPriority( int newPriority ) :设置线程的优先级

2.getPriority( ):获取线程的优先级

默认情况下,main主线程默认为NORM_PRIORITY普通优先级,其值为5。

线程插队之join方法

  join方法:一个线程A插队到一个线程B之前,线程A阻塞

返回值类型方法解释
voidjoin()等待该线程终止。
voidjoin(long millis)等待该线程终止的时间最长为 millis 毫秒
voidjoin(long millis, int nanos)等待该线程终止的时间最长为 millis 毫秒 + nanos 纳秒

线程A:

public class ThreadA extends Thread{    private ThreadB tb;    public void setTb(ThreadB tb){        this.tb = tb;    }    @Override    public void run() {        for( int i = 0 ; i < 100 ; i++ ){            System.out.println("ThreadA------------"+i);            try {              //线程tb使用join方法,插队到线程ta之前              //无参数的join方法,使用时是等到插队线程(tb)执行完成之后,才能执行被插队的线程(ta)          //带参数的join方法,使用时是等到插队线程(tb)的插队时间完成之后,去执行被插队的线程(ta)                tb.join(1);            } catch (InterruptedException e) {                e.printStackTrace();            }        }    } }

线程B:

public class ThreadB extends Thread{    public void run() {        for( int i = 0 ; i < 100 ; i++ ){            System.out.println("ThreadB----"+i);        }    } }

测试:

import com.thread.join.ThreadA;   import com.thread.join.ThreadB;   public class TestJoin {   public static void main(String[] args)

{        ThreadA ta = new ThreadA();        ta.start();        ThreadB tb = new ThreadB();        tb.start();        ta.setTb(tb);    } }