Java----线程学习(多线程)

Java----线程学习(多线程)

1.线程的五个状态:
-创建状态:Thread t=new Thread(),创建了一个线程,此时该线程就是创建状态
-就绪状态():当t线程调用了start()方法,线程立即进入就绪状态,在就绪状态队列中的线程不一定会立即执行,取决于cpu的调度
-运行状态:当cpu调度后,线程进入运行状态,执行重写的run方法的线程体代码块
-阻塞状态:当系统调用sleep(),wait,或者同步锁定时,线程进入阻塞状态,代码不往下执行,等待阻塞解除后,重新进入就绪状态,等待cpu的再次调度
-死亡状态:线程中断或结束,进入死亡状态后便不能再次启动了
JDK文档中这样描述:
线程可以处于以下状态之一:
●NEW 尚未启动的线程处于此状态。
●RUNNABLE 在Java虚拟机中执行的线程处于此状态。
●BLOCKED 被阻塞等待监视器锁定的线程处于此状态。
●WAITING 正在等待另一个线程执行特定动作的线程处于此状态。
●TIMED WAITING 正在等待另一个线程执行动作达到指定等待时间的线程处于此状态。
●TERMINATED 已退出的线程处于此状态。
一个线程可以在给定时间点处于一个状态。这些状态是不反映任何操作系统线程状态的虚拟机状态。
测试代码:

package edu.ncu.dong.Thread.method;
//线程状态测试
public class TestState {
    public static void main(String[] args) throws InterruptedException {
        Thread thread=new Thread(()->{
                try {
                    for (int i = 0; i < 5; i++) {
                        Thread.sleep(500);
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
        });
        //观察状态
        Thread.State state=thread.getState();
        System.out.println(state);//new
        thread.start();
        state=thread.getState();
        System.out.println(state);//runnable
        while (state!=Thread.State.TERMINATED){
            Thread.sleep(500);
            state=thread.getState();
            System.out.println(state);//TIMED_WAITING
        }
        //thread.start();//不能再启动
    }
}

结果如图:
在这里插入图片描述
注意的是已经处于死亡状态的线程不能重新启动:比如在main方法最后加上thread.start()就会报错:
在这里插入图片描述

2.线程常用方法

方法说明
setPriority(int newPriority)更改一个线程的优先级
static void sleep(long millis)指定当前线程休眠,参数以毫秒记
void jion()等待该线程终止
static void yield()暂停当前正在执行的线程对象,并执行其他线程
static void yield()暂停当前正在执行的线程对象,并执行其他线程
void interrupt()中断线程(不推荐使用)
boolean isAlive()测试线程是否处于活动状态

1)线程的终止
不推荐使用JDK提供的stop(),destroy()方法(已废弃),推荐让线程自己停止下来,建议使用一个标志位进行终止变量当flag=false,则终止线程运行。

package edu.ncu.dong.Thread;
import com.sun.scenario.effect.impl.sw.java.JSWBlend_SRC_OUTPeer;
//测试使用线程终止
public class TestStop implements Runnable{
    //1.设置一个标志位
    private boolean flag=true;
    @Override
    public void run() {
        int i=1;
        while(flag){
            System.out.println("这是第"+(i++)+"次");
        }
    }
    //2.设置一个自定义方法停止线程
    public void stop(){
        this.flag=false;
    }
    public static void main(String[] args) {
        TestStop test=new TestStop();
        new Thread(test).start();
        for (int i = 0; i < 500; i++) {
            System.out.println("main:"+"   "+i);
            if (i==400){
                //自己利用flag停止线程
                test.stop();
                System.out.println("线程该停止了");
            }
        }
    }
}

运行结果:
运行结果
2)进程休眠 sleep()
-sleep (时间)指定当前线程阻塞的毫秒数;
-sleep存在异常InterruptedException;
-sleep的时间达到后线程进入就绪状态;
-sleep可以模拟网络延时,倒计时等。
-每一个对象都有一个锁,sleep不会释放锁;
用sleep()模拟网络延时:这是个模拟的抢票系统

package edu.ncu.dong.Thread.method;
//模拟网络延时
public class TestSleep implements Runnable{
    private Integer tickets=5;//当前票数
    //线程执行体
    @Override
    public void run() {
        while (true) {
            if (tickets < 0)
                break;//这里先判断:至少还有一张票,才模拟下面的抢票操作
            System.out.println(Thread.currentThread().getName() + "执行了抢票操作,还有第" + tickets-- + "张票");
        }
    }
    public static void main(String[] args) {
        TestSleep test=new TestSleep();
        new Thread(test,"东东").start();//第二个参数是自定义线程的名字
        new Thread(test,"兰兰").start();
        new Thread(test,"丽丽").start();
    }
}

结果
结果中可以看出,这个“丽丽”线程明显执行时间过长,别的两位无法抢票,所以我们改一下代码,模拟网络延时:

public void run() {
        while (true) {
            if (tickets < 0)
                break;//这里先判断:至少还有一张票,才模拟下面的抢票操作
            try{
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "执行了抢票操作,还有第" + tickets-- + "张票");
        }
    }

执行结果友好得多:
在这里插入图片描述
3)线程礼让yield()
-礼让线程:让当前正在执行的线程暂停,但不阻塞(阻塞是转为阻塞态)
-作用:将线程从运行状态转为就绪状态,让cpu重新调度,礼让不一定成功!看CPU的调度
测试代码:

package edu.ncu.dong.Thread.method;
//测试yield方法
public class TestYield {
    public static void main(String[] args) {
        //这里就用lambda表达式简写了
        Runnable r=()->{
            System.out.println("线程:"+Thread.currentThread().getName()+"  开始!");
            Thread.yield();//礼让
            System.out.println("线程:"+Thread.currentThread().getName()+"  结束!");
        };
        new Thread(r,"T1").start();
        new Thread(r,"T2").start();
    }
}

结果:礼让成功
结果
再次运行结果:礼让失败
结果
4)合并线程jion()
-这个方法很霸道:等待此线程执行完成后,再执行其他线程,其他线程阻塞
测试代码:

package edu.ncu.dong.Thread.method;
public class TestJoin {
    public static void main(String[] args) throws InterruptedException {
        Runnable r=()->{
            for (int i = 0; i < 5; i++) {
                System.out.println("正在执行vip线程"+i);
            }
        };
        Thread t=new Thread(r);
        t.start();//此时start之后,t线程就已经处于就绪状态(runnable状态)了,所以cpu是可以调度执行t的run代码块的
        for (int i = 0; i < 200; i++) {
            System.out.println("main线程执行中"+i);
            if(i==100)
                //此时i等于了100,执行了join方法,main进入阻塞,直到t线程结束,所所以可能出现的情况是:
                //t线程在join方法执行之前已经结束了(dead),此时就不会调用t线程了
                t.join();
        }
    }
}

结果:
在这里插入图片描述
注意点:
代码中t.start():此时start之后,t线程就已经处于就绪状态(runnable状态)了,所以cpu是可以调度执行t的run代码块的
而另一方面: t.join();此时i等于了100,执行了join方法,main进入阻塞,直到t线程结束,所以可能出现的情况是:t线程在join方法执行之前已经结束了(dead),此时就不会调用t线程了。
如图:我把t线程的i调为5,此时线程t很快就结束了,而主线程就不会阻塞去调用t线程了。
在这里插入图片描述
5)线程优先级
Java提供一 个线程调度器来监控程序中启动后进入就绪状态的所有线程,线程调度器按照优先级决定应该调度哪个线程来执行。线程的优先级用数字表示,范围从1~10,默认为5。
方法名:void setPriority(int newPriority)
查看例子:

package edu.ncu.dong.Thread.method;

public class TestPriority {
    public static void main(String[] args) {
        System.out.println(Thread.currentThread().getName()+" its priority is : "+Thread.currentThread().getPriority());
        MyPriority myPriority=new MyPriority();
        Thread thread1=new Thread(myPriority);
        thread1.setPriority(6);
        Thread thread2=new Thread(myPriority);
        thread2.setPriority(7);
        Thread thread3=new Thread(myPriority);
        thread3.setPriority(8);
        Thread thread4=new Thread(myPriority);
        thread4.setPriority(9);
        Thread thread5=new Thread(myPriority);
        thread5.setPriority(10);//10是最大的优先级

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

class MyPriority implements Runnable{
    @Override
    public void run() {
        try {
            Thread.sleep(1*1000);//延时,帮助cpu在调度其他线程时,当前线程还没结束
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        finally {
            System.out.println(Thread.currentThread().getName()+" its priority is : "+Thread.currentThread().getPriority());
        }
    }
}

查看结果
在这里插入图片描述
可以发现,虽然Thread-4是最大优先级10,确实先于其他(除了主线程)线程运行了,但是看红色2处可以发现:并不一定优先级高就先执行,比如Thread-2先于Thread-3先执行,优先级只是会起到一定的作用。优先级低只是意味着获得调度的概率低,并不是优先级低就不会被调用了,这都是看CPU的调度。

6)守护线程(deamon)
线程分为用户线程和守护线程;虚拟机必须确保用户线程执行完毕(也就是说有用户线程存在时,JVM就会存活),但是不用等待守护线程执行完毕。守护线程的优先级比较低,用于为系统中的其它对象和线程提供服务。如,后台记录操作日志,监控内存,垃圾回收等待…
查看例子:

package edu.ncu.dong.Thread.method;
/**
 * 测试守护线程
 */
public class TestDaemon {
    public static void main(String[] args) {
        /*
         * 神在守护我们来模拟守护线程
         */
        Godness godness=new Godness();//神
        We we=new We();//平凡人
        Thread threadGod=new Thread(godness);
        threadGod.setDaemon(true);//默认false,表示用户线程,true表示设置为守护线程
        Thread threadWe=new Thread(we);
        //启动线程
        threadGod.start();//守护线程
        threadWe.start();//用户线程
    }
}

class Godness implements Runnable{
    @Override
    public void run() {
        while (true){
            System.out.println(" God bless us!");
        }
    }
}

class We implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 3000; i++) {
            System.out.println(" happy every day!");
        }
        System.out.println(" good bye !");
    }
}

我们查看运行结果:
在这里插入图片描述
这里各自获得cpu的调度执行
在这里插入图片描述
这里We线程(用户线程)执行结束,Godness线程还在执行
在这里插入图片描述
一段时间后,Godness也结束了,由于Godness线程是个While(true)死循环,不应该结束,但是由于它是守护线程,所以当没有用户线程存在时,守护线程也就随即结束。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值