线程一些小知识的整理。
一:设置线程的优先级
需求: 定义两个线程,对线程的优先级别进行设置,并运行!
技能: 引入线程的控制方法--- setPrirority(int i) getPrirority();
1.设计线程的优先级别的方法
1.1 public final void setPriority(int newPriority)
注意: 被final修饰的方法,只能被继承不能被重写!(也可以重载)
参数---int newPriority 1 5 10
在Thread当中,存在以下几个常量:
线程可以具有的最高优先级。
public static final int MAX_PRIORITY 10
分配给线程的默认优先级。
public static final int NORM_PRIORITY 5
线程可以具有的最低优先级。
public static final int MIN_PRIORITY 1
问题: 能否直接写整数常量? 可以的
问题: 写入负整数以及0会出现什么情况? 输入的是7或8这些会出现什么情况?
推荐怎么传入实参?
1.输入负数,虽然符合int 的取值范围,但是在后台运行时,出现非法参数异常---IllegalArgumentException
2.发现:优先级别的范围: 1--10之内的,包括1也包括10
3.以后在输入实参时,建议使用Thread类当当中的常量
Thread.MAX_PRIRORITY Thread.MIN_PRIRORITY Thread.NORE_PRIRORITY
1.2 public final int getPriority()
发现:返回值类型是int类型 传入的是什么优先级,返回的就是多少。
2.由于线程具有并发性以及随机性,即使设置的某个线程的优先级别最高,也不一定先执行!
原因: ① 随机性
② 每一个线程都会循环得到自己的时间片,都会抢CPU资源,谁抢到了谁先运行!
既然不能保证线程优先执行,为什么还要进行设置?
原因:虽然不能保证优先界别最高的线程先执行,但是他优先执行的概率是很大的!
3.main方法也是属于线程,它的优先级别是默认的,也就是5
代码区:
public class TestPriroprity {
public static void main(String[] args) {
//1.创建Runnable接口对象
Runnable r1 = new Tiger();
Runnable r2 = new Cat();
//2.借助Thread类,创建线程对象
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
//线程的优先级
// t1.setPriority(Thread.MAX_PRIORITY);
// t2.setPriority(Thread.MIN_PRIORITY);
t1.setPriority(7);
t2.setPriority(8);
System.out.println(t1.getPriority());
System.out.println(t2.getPriority());
//获取main方法也就是主线程的名称和优先级别
System.out.println(Thread.currentThread().getName());
int pri=Thread.currentThread().getPriority();
System.out.println("pri="+pri);
//3.启动线程
t1.start();
t2.start();
}
}
class Tiger implements Runnable{
@Override
public void run() {
System.out.println("Tiger线程优先级别是最高级---MAX_PRIRORITY");
}
}
class Cat implements Runnable{
@Override
public void run() {
System.out.println("Tiger线程优先级别是最低级---MIN_PRIRORITY");
}
}
二:线程的强制加入
需求: 在你做一件好事的时候,即将完成,突然---半路杀出个程咬金
技能: 线程控制方法----强制加入
1.强制加入的方法---join();
public final void join() throws InterruptedException
发现: 使用final修饰以及抛出了异常(中断异常)
2.时时刻刻要记住----main方法也是一个线程
3.思路步骤:
3.1 先创建一个线程类(创建线程对象),最好实现Runnable接口
3.2 重写run()方法,在run()方法内部,定义一个for循环(有限循环)
3.3 在main方法当中,定义一个for循环---循环次数20次,当循环到10次的时候,另外一个线程强制加入!
发现:只有强制加入的线程执行完毕之后,其他的线程才能继续运行,反之,其他线程不能执行!
代码区:
public class TestJoinThread {
//主方法也是一个线程
public static void main(String[] args) {
//创建ChengYaoJin线程对象
Runnable r = new ChengYaoJin();
Thread t = new Thread(r);
for(int i=1;i<=20;i++){
System.out.println("牛荣君超级大美女-----自恋"+i);
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
//当循环到第10次的时候,阚天阳来了....
if(i==10){
//启动线程
t.start();
//强制加入,由于此方法抛出异常,所以在调用时必须对异常进行处理----try catch捕捉异常
try {
t.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
class ChengYaoJin implements Runnable{
//重写接口当中的run()方法
public void run() {
//因为run方法是线程的主体,所以要把核心代码放入到此方法中
for(int i=1;i<=10;i++){
System.out.println("谁拿走了我的八块腹肌----阚天阳"+i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
三:线程休眠:
需求1: 运动会---裁判 预备 1 2 3 开始
技能1: 引入线程的控制方法---线程休眠
需求2: 定义一个时间,时间的格式: HH:mm:ss,每隔一秒进行打印一次!
技能2: 引入线程的控制方法---线程休眠
1.线程休眠的方法
public static void sleep(long millis)throws InterruptedException
发现: 此方法使用static修饰,所以可以使用类名称直接调用。此方法抛出异常,所以在调用时必须处理异常---捕捉异常。
2.此方法的作用
2.1 线程进行堵塞状态,休眠时间结束,会在次进入就绪状态,参与分配CPU资源,运行线程!
2.2 可以被变相的看成是一个转换器---例如: 两个线程交叉运行 线程A运行一次,线程B运行一次,以此类推
体现: 在定义两个线程时,在run方法当中,插入线程休眠的方法,具体看实例!
如果想具体的保证两个线程的交叉允许,可以使用同步锁完成!
3.方法的参数
long millis --- 毫秒数 单位的换算 1000毫米=1秒
代码区:
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
public class TestSleepThread {
public static void main(String[] args) {
//1.时间格式化类---DateFormat SimpleDateFormat()
DateFormat df = new SimpleDateFormat("HH:mm:ss");
//2.定义while循环,目的: 打印时间
while(true){
//打印时间,必须有一个Date类对象
Date d = new Date();
//DateFormat类存在一个format(Date d) 返回值是String类型
String now=df.format(d);
System.out.println(now);
//每隔一秒进行打印输出时间
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public static void show(){
//1.裁判应该先喊: 各就各位 预备
System.out.println("各就各位 预备..............");
//2.等待三秒,三秒已过,立即开始执行....
for (int i = 1; i < 4; i++) {
System.out.println(i);
//每一次输出i的值,需要间隔一秒
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//3.开始
System.out.println("开始....................");
}
}
四:线程的礼让
需求: 古装剧------西门大官人 林娘子 潘娘子, 定义两个线程,每一个线程要交叉运行,一个线程喊: 官人 一个线程喊: 娘子
技能: 线程礼让的方法----yield();
1.线程礼让----yield方法
暂停当前正在执行的线程对象,并执行其他线程。
public static void yield()
发现: 此方法没有抛出异常,同时使用static修饰,所以类名称可以直接调用!
特点: 暂停正在执行的线程,让其他线程先执行,而且此方法不是阻塞线程,而是将线程转入---就绪状态,不是阻塞状态
continue --- 结束本次循环,执行下一次循环
yield() --- 让出当前的CPU资源,让其他的线程优先执行!
2.线程要交叉运行--- 解决方案
2.1 使用的是线程的休眠---发现: 并不一定按照交叉运行,可能是某一个线程执行完毕,另外一个线程才执行。
2.2 使用线程的礼让,但是呢,它也不能保证线程的交叉运行,只是一定程度上,可以实现,如果想线程之间真正的交叉允许,需要使用线程同步。
3.步骤:
3.1 创建线程---一个线程充当: 男友 -- 官人
一个线程充当: 女友 -- 娘子
实现的方式: 先通过继承的方式,在使用实现Runnable接口的方式
3.2 要重写run()方法---不管是继承Thread类也好,还是实现Runnable接口也好,都要重写run()方法
原因: 因为run()方法,是线程的主体,核心代码放入到此方法中。
3.3 在重写的过程当中,可以使用线程休眠也可以使用线程礼让
3.4 在main方法当中,创建线程,并启动线程!
public class TestYieldThread {
public static void main(String[] args) {
//1.创建线程对象
Thread t1 = new GuanRen();
Thread t2 = new NiangZi();
//2.为线程命名
t1.setName("\t潘娘子");
t2.setName("西门大官人");
//3.启动线程
t1.start();
t2.start();
}
}
//创建线程类,通过继承Thread类实现
class GuanRen extends Thread{
//重写run()方法
public void run(){
//for循环语句 目的: 为了实现交叉运行,肯定有一个定喊话次数
for(int i=1;i<=10;i++){
System.out.println(this.getName()+"喊:官人.....");
//切换 -- sleep();
// try {
// Thread.sleep(1000);
// } catch (InterruptedException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
//线程的礼让
Thread.yield();
}
}
}
class NiangZi extends Thread{
//重写run()方法
public void run(){
//for循环语句 目的: 为了实现交叉运行,肯定有一个定喊话次数
for(int i=1;i<=10;i++){
System.out.println(this.getName()+"喊:娘子.....");
//切换 -- sleep();
// try {
// Thread.sleep(1000);
// } catch (InterruptedException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
//线程的礼让
Thread.yield();
}
}
}
五:设置线程为后台线程
需求: 在main方法当中,创建线程,并设置线程为后台线程,main方法运行结束之后,后台线程也随之结束!
技能: 线程的控制方法-----后台线程。
1.设置线程为后台线程
public final void setDaemon(boolean on)
将该线程标记为守护线程或用户线程
发现:1.此方法使用final修饰 2. 没有抛出异常 3. 参数类型是布尔值,如果是true则设置为后台线程,反之,是前台线程。
2.后台线程---前台线程
后台线程又被称为守护线程,前台线程又被称为用户线程!
注意: 咱们一般创建的线程都是用户线程,特别说明: main方法时一个用户线程
后台线程----最典型的例子就是GC---垃圾回收器
3.设置线程为后台线程,必须是在线程的启动之前,也就是start()方法之前进行设置!
代码区:
public class TestSetDeamonThread {
//主方法不仅是一个线程,还是一个用户线程(前台线程)
public static void main(String[] args) {
//1.创建线程对象
Runnable r = new QianJinHui(); //目的: 为Thread类创建对象,做准备
Thread t = new Thread(r); //根据构造方法,传入Runnable接口对象
//2.设置后台线程
t.setDaemon(true);
//3.启动线程
t.start();
//4.也写一个for循环,for循环执行结束,后台线程也随之结束,即使后台线程中的run方法嵌套了一个死循环,也要结束
for(int i=1;i<=5;i++){
System.out.println("周日计划----休眠"+i);
}
}
}
//创建一个线程类
class QianJinHui implements Runnable{
//重写run()方法
public void run() {
//为了体现出: 前台线程结束之后,后台线程也随之结束,写一个死循环
while(true){
System.out.println("上课玩手机,该罚-----十个俯卧撑!");
}
}
}
原博地址(也是我,O(∩_∩)O哈哈~):http://m15231417197.lofter.com/
练习代码地址(嘿嘿嘿):https://download.csdn.net/download/m15231417197/10716486