JAVA多线程(1)

进程的状态与生命周期

要想实现多线程就要在主线程中创建新的线程 新建的线程在他的一个完整的生命周期内通常要经历五种状态 通过线程的控制与调度可使线程在这几种状态之间转化

  1. 新建状态 : Thread 或者其子类的对象被声明并创建 但是还没有被执行的这段时间里面 处于一种特别的新建状态中 这时候线程对象已经被分配了内存空间和其他的资源 并且已经被初始化 但是该线程已经没有被调度 此时的线程可以被调度 变成了就绪状态
  2. 就绪状态 : 也可以叫可运行状态 处于新建状态的线程被启动后 将进入线程队列等待CPU资源 这时候他已经有了运行的条件 也就是处于了就绪状态 等到他来使用CPU资源的时候 就可以脱离主线程开始自己的生命周期
  3. 执行状态 : 当就绪状态的线程被调度并获得cpu 资源时候 就进入了执行状态 该状态表示线程正在执行 它拥有了cpu的控制权 每一个Thread类和他的子类对象都有一个重要的run()方法 该方法定义了这一类线程的操作和功能 当 线程被调度时候 他将自动的调用本对象的run()方法 从该方法的第一条开始运行一直到最执行完毕
    除非是线程主动的让出cpu的控制权或者cpu的控制权被优先级更高的线程抢占
  4. 阻塞状态 :一个正在执行的线程由于某种特殊的情况 将让出cpu 并且中止自己的执行 线程处于这样的状态被称为阻塞状态
    在这种状态下即使cpu空闲也不能执行线程 进入阻塞的方法:
    调用sleep()或者yield()方法
    为了等待一个条件变量 ,线程调用wait()方法
    该线程和另一个线程join()在一起了

    处于阻塞状态的线程通常会想要某些事件唤醒
  5. 消亡状态: 处于消亡状态的线程不具有继续执行的能力
    消亡的原因有:
    正常的运行的线程完成了全部的任务
    进程因故停止后 线程被强行终止

    线程消亡状态 并且没有线程对象引用后 垃圾回收器 会从内存里面删除线程对象

Thread线程类和Runnable接口

实现多线程的方法有 两个
一个是java.lang的Thread 类
一个是用户在定义自己的类中实现Runnable 接口

利用Thread 类的子类来创建线程

要在一个Thread的子类里面激活线程 需要注意 这个类必须继承Thread类 和线程要执行的代码必须写在run()里面

class 类名 extends Thread{
    // 成员变量
    //成员函数
    //修饰符 +run()
    {
		// 线程的代码
    }
}

利用Thread 类的子类创建线程

public class myThread extends  Thread {
    private  String who;
    public  myThread(String str){
        who = str;
    }
    public void run(){
        for (int i=0 ;i<5;i++)
        {
            try {
                sleep((int)(1000*Math.random()));
            }catch (InterruptedException e){

            }
            System.out.println(who+"正在运行!");
        }
    }

    public static void main(String[] args) {
        myThread you = new myThread("你");
        myThread she = new myThread("她");
        you.start();    // 调用的不是run()哦
        she.start();
        System.out.println("主方法main()运行结束");
    }


}

}

结果:

主方法main()运行结束
你正在运行!
你正在运行!
她正在运行!
你正在运行!
她正在运行!
你正在运行!
她正在运行!
你正在运行!
她正在运行!
她正在运行!

main 也是一个线程 执行完成you.start()和she.start()后继执行
至于 先输出运行结束还是进入start() 全部看是谁抢到了cpu资源
(本人测试一直是运行先出来 刚开始一直是以为输出运行结束的那一句先出来 后来才知道最后的输出运行结束不需要线程激活的过程 所以一般先运行)

用Runnable接口来创建线程

Thread 直接继承了Object 类 实现了Runnable接口 所以他的子类都有线程功能 所以用户可以直接声明一个类并且实现Runnable接口
并且定义run()方法 但是Runnable的接口没有任何的对线程支持 所以还必须创建一个Thread的实例

Runnable接口的好处不仅在于它间接的解决的多重继承的问题 和Thread相比 Runnable接口更加的适合于多个线程解决同一资源

在这里插入代码片
public class myThread2 implements  Runnable{
    private  String who;
    public  myThread2(String str){
        who = str;
    }
    @Override
    public void run() {
        for (int i=0 ;i<5;i++)
        {
            try {
                Thread.sleep((int)(1000*Math.random()));
            }catch (InterruptedException e){
                System.out.println(e.toString());
            }
            System.out.println(who+"正在运行!");
        }
    }

    public static void main(String[] args) {
        myThread2 you = new myThread2("你");
        myThread2 she = new myThread2("她");
        Thread t1 = new Thread(you);
        Thread t2 = new Thread(she);
        t1.start();
        t2.start();

    }

}

该代码的功能和上面的基本相同

如果需要有序的运行
需要使用Thread中的join()的方法
当某一个线程调用join()方法的时候 其他的线程需要等待她运行结束才会开始执行

在这里插入代码片
public class myThread extends  Thread {
    private  String who;
    public  myThread(String str){
        who = str;
    }
    public void run(){
        for (int i=0 ;i<5;i++)
        {
            try {
                sleep((int)(1000*Math.random()));
            }catch (InterruptedException e){

            }
            System.out.println(who+"正在运行!");
        }
    }

    public static void main(String[] args) {
        myThread you = new myThread("你");
        myThread she = new myThread("她");
        you.start();    // 调用的不是run()哦
        try {
            you.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        she.start();
        try {
            she.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("主方法main()运行结束");
    }


}

结果
你正在运行!
你正在运行!
你正在运行!
你正在运行!
你正在运行!
她正在运行!
她正在运行!
她正在运行!
她正在运行!
她正在运行!
主方法main()运行结束

通过继承Thread 类的优点是编写简单 直接的操作线程 缺点是继承了Thread 就不能继承其他类

线程之间的数据共享

例如
有3个售票窗口 共有5个票 出售火车票

public class Threadsale extends Thread {
    private  int tickets = 5;

    @Override
    public void run() {
        while (true){
            if (tickets>0){
            System.out.println(this.getName()+"售票机"+tickets--+"号票");
            }else{
                System.exit(0);
            }

        }
    }

    public static void main(String[] args) {
        Threadsale t1 = new Threadsale();
        Threadsale t2 = new Threadsale();
        Threadsale t3 = new Threadsale();
            t1.start();
            t2.start();
            t3.start();
    }
}

结果

Thread-1售票机5号票
Thread-2售票机5号票
Thread-2售票机4号票
Thread-2售票机3号票
Thread-2售票机2号票
Thread-2售票机1号票
Thread-0售票机5号票
Thread-0售票机4号票
Thread-0售票机3号票
Thread-0售票机2号票
Thread-0售票机1号票
Thread-1售票机4号票
Thread-1售票机3号票
Thread-1售票机2号票
Thread-1售票机1号票

你会发现一张票同时出售了3次 着明显是不合理的
创建的3个线程都有自己的资源 他们之间没有共享资源

用Runnable接口来完成

在这里插入代码片
public class Threadsale extends Thread {
    private  int tickets = 5;

    @Override
    public void run() {
        while (true){
            if (tickets>0){
            System.out.println(Thread.currentThread().getName()+"售票机"+tickets--+"号票");
            }else{
                System.exit(0);
            }

        }
    }

    public static void main(String[] args) {
       /* Threadsale t1 = new Threadsale();
        Threadsale t2 = new Threadsale();
        Threadsale t3 = new Threadsale();
            t1.start();
            t2.start();
            t3.start(); */
       Threadsale t = new Threadsale();
               Thread t1 = new Thread(t,"第一个窗口");
               Thread t2 = new Thread(t,"第二个窗口");
               Thread t3 = new Thread(t,"第三个窗口");
               t1.start();
               t2.start();
               t3.start();


    }
}

结果:

第一个窗口售票机4号票
第二个窗口售票机3号票
第三个窗口售票机5号票
第二个窗口售票机1号票
第一个窗口售票机2号票

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值