Java学习笔记 - 线程使用


进程与线程


进程:即运行中的程序,一个进程有着 产生、存在、消亡 的完整过程。
线程:是进程的一个分支,一个进程可以拥有多个线程。当然一个线程也可以产生多个子线程分支

例如:打开一个QQ,就是创建了一个进程,一个QQ里面有多个聊天界面,每个聊天界面就可以理解为一个线程。


一、线程的基本使用


1、创建线程

创建线程有两种常用方式:
1.继承Thread类
2.实现Runnable接口

(1)继承Thread类,并重写run方法

class A extends Thread{
    @Override
    public void run() {
        //写需要执行的业务代码
    }
}

使用时创建a对象,调用start方法(它的内部会自行调用run方法)启动线程

public class Text {
    public static void main(String[] args) {
        A a = new A();
//      a.run();//这只是调用了run方法,并没有实现线程的创建
        a.start();
    }
}

(2)实现Runnable接口,并重写run方法

class A implements Runnable{
    @Override
    public void run() {
        //写需要执行的业务代码
    }
}

使用时创建A对象,不能直接调用start方法启动线程,需要先创建一个Thread对象,把a对象放入Thread对象中,让其进行代理,再使用新建的Thread对象调用start方法启动线程

public class Text {
    public static void main(String[] args) {
        A a = new A();
//创建thread对象并把a对象放进去
        Thread thread = new Thread(a);
        thread.start();
    }
}

说明:
因为Java时单继承机制的,有时候一个类可能已经继承了别的父类,导致其不能通过 继承Thread 的方式来创建线程,此时,就只能通过第二种方式, 实现Runnable接口 来创建线程了。


继承Thread 与 实现Runnable接口的区别:

  1. 从Java的设计来看, 继承Thread 与 实现Runnable接口来创建线程没有本质上的区别,因为看JDK文档会发现Thread类本身就是实现了Runnable接口的
  2. 实现Runnable接口的方式更加适合多个线程共享一个资源的情况,且避免了单继承的限制,所以推荐使用实现Runnable接口的方式创建线程

实现Runnable接口的方式更加适合多个线程共享一个资源,示例代码:

public class Thread01 {
    public static void main(String[] args) {//主线程
        T1 t1 = new T1();
        T2 t2 = new T2();
        Thread thread1 = new Thread(t1);
        Thread thread2 = new Thread(t2);
        thread1.start();//启动第1个子线程
        thread2.start();//启动第2个子线程
        //...
        //threadn.start();//启动第n个子线程
        System.out.println("主线程结束。");
    }
}

2、线程终止

1、当线程执行完它自己的所有语句时,自动退出,结束线程
2、可以通过使用变量来控制run方法退出的方式停止线程,即通知方式

public class Thread02 {
    public static void main(String[] args) throws InterruptedException {
        T t1 = new T();
        Thread thread = new Thread(t1);
        thread.start();

        //如果希望main线程去控制 thread 线程的终止
        //则需要修改 key 的值来终止线程

        //让主线程休眠 10 秒后就通知 thread线程 退出
        Thread.sleep(10 * 1000);
        t1.setKey(false);//此语句执行完,子线程 thread 被终止
    }
}

class T implements Runnable {
    //设置一个控制变量key
    private boolean key = true;
    @Override
    public void run() {
        while (key) {//key值一直为true,则线程永远不会结束
            try {
                Thread.sleep(50);// 让当前线程休眠50ms
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    public void setKey(boolean key) {
        this.key = key;
    }
}

二、线程的常用方法

1、setName:设置线程的名称,使之与参数name相同
2、getName:返回该线程的名称
3、start:开始执行线程(在Java虚拟机底层调用该线程的start0方法)
4、run:调用该线程的run方法
5、setPriority:更改线程的优先级
6、getPriority:获取线程的优先级
7、sleep:让该线程休眠指定秒数(单位:毫秒,1秒=1000毫秒)
8、interrupt:中断线程(不是终止),常用于中断线程的休眠

线程的优先级,有以下几种:

9、yield:线程的礼让,即让出cpu给其它线程执行,但是礼让时间不确定,不一定礼让成功。可以理解为给出了一个礼让的动作,礼让是否成功得看具体情况
10、join:线程的插队。线程一旦插队成功,就一定是插队的线程线执行完所有任务,再执行被插队的线程未执行完的任务


三、用户线程与守护线程

1、用户线程:也叫工作线程,当线程 执行完毕 或 被通知结束(通知方式)时结束
2、守护线程:一般是为工作线程服务的,当所有的用户线程结束后,守护线程自动结束。如:家长监督孩子(用户线程)做作业,作业做完了,家长也就离开了
3、常见的守护线程:垃圾回收机制

用户线程与守护线程,代码案例:

public class ThreadMethodExercise {
    public static void main(String[] args) throws InterruptedException {//孩子线程
        Thread parent = new Thread(new Parents());//家长线程
        //如果我们希望当孩子线程结束后,家长线程自动结束
        //只需将家长线程设为守护线程即可
        parent.setDaemon(true);
        parent.start();

        for( int i = 1; i <= 10; i++) {//孩子线程,10本作业
            System.out.println("小孩在疯狂的写了 " + i + " 本作业");
            Thread.sleep(100);//1本作业时长
            if(i == 10){
                System.out.println("小孩作业写完了,家长离开");//做完后,家长线程就随之结束了
            }
        }
    }
}

class Parents implements Runnable {
    private int times = 0;//监督时长

    @Override
    public void run() {
        while (true) {
            try {
                Thread.sleep(200);//休眠200毫秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("家长监督小孩了 " + (++times * 200) + "毫秒");
        }
    }
}
运行结果:

小孩在疯狂的写了 1 本作业
小孩在疯狂的写了 2 本作业
家长监督小孩了 200毫秒
小孩在疯狂的写了 3 本作业
小孩在疯狂的写了 4 本作业
家长监督小孩了 400毫秒
小孩在疯狂的写了 5 本作业
小孩在疯狂的写了 6 本作业
家长监督小孩了 600毫秒
小孩在疯狂的写了 7 本作业
小孩在疯狂的写了 8 本作业
家长监督小孩了 800毫秒
小孩在疯狂的写了 9 本作业
小孩在疯狂的写了 10 本作业
家长监督小孩了 1000毫秒
小孩作业写完了,家长离开

四、线程的7种状态

线程可以处于以下状态之一:
1、NEW
尚未启动的线程处于此状态。
2、RUNNABLE
在Java虚拟机中执行的线程处于此状态。
3、BLOCKED
被阻塞等待监视器锁定的线程处于此状态。
4、WAITING
正在等待另一个线程执行特定动作的线程处于此状态。
5、 TIMED_WAITING
正在等待另一个线程执行动作达到指定等待时间的线程处于此状态。
6、TERMINATED
已退出的线程处于此状态。

RUNNABLE状态又可细分为Ready状态和Running状态,故认为有7种状态。

一个线程可以在给定时间点处于一个状态。 这些状态是不反映任何操作系统线程状态的虚拟机状态。

想知道线程当前状态,可通过调用getState方法来返回线程的当前状态值


  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值