Java多线程机制

java线程:

多线程是指一个应用程序中同时存在几个执行体,但是我们的计算机在任何给定的时刻只能执行那些线程中的一个。

主线程:

java应用程序总是主类的main方法开始执行,当JVM加载代码,发现main方法之后,就会开启一个线程“主线程”,当main方法执行完最后一个语句,即main方法返回时,JVM就要结束java应用程序。

线程的状态和生命周期:

ava语言使用Thread类以及子类的对象来表示线程。
线程有4种状态,分别为新建,运行,中断,死亡
新建:创建对象并且声明时
运行:线程创建之后就具备了运行的条件,但线程创建后仅仅是占有了内存资源,在JVM管理的线程中还没有这个线程,此线程必须调用start()方法通知JVM,此时JVM就知道又有一个新的线程等候切换。当JVM将cpu使用的权限切换给线程时,该类中的run()方法就立刻被执行,run()方法中规定了该线程的具体使命。
中断:有4中原因的中断
1>JVM将cpu资源的使用权从当前线程切换给其他的线程
2>线程使用cpu期间,执行了sleep(int ,illsecond)方法,使线程进入睡眠的状态,线程一旦执行了sleep()方法,就立刻让出cpu资源的使用权,当指定的毫秒之后,该线程就重新进入到线程队列中等候cpu资源。
3>线程使用cpu资源期间,执行了wait()方法,使得该线程进入到等待状态。等待状态的线程不会主动进入到线程队列中排队等待cpu资源,必须由其他的线程调用notify()方法通知它,使其从中断处继续运行。
4>线程使用cpu资源期间,执行某个操作进入到了阻塞状态,
死亡:处于死亡状态的线程不具有继续运行的能力。
1>正常运行的线程完成了全部的工作
2>线程被提前强制性的终止了

线程调度与优先级 :

处于就绪状态的线程首先进入就绪队列排队等候CPU资源,那么同时处于就绪状态的线程可能有多个、java虚拟机中的线程调度器负责管理线程,它把线程的优先级分成10个级别,分别用Thread类中的类常量表示。即Thread.MIN_PRIORITY 和Thread.MAX_PRIORITY之间,如果没有明确的设置线程的优先级,默认为5.如果A,B,C,D四个线程,A和B线程的优先级别高于C和D,那么java调度器首先以轮流的方式执行A和B,一直到A,B都执行到死亡的状态,才会在C,D之间轮流的切换。

Thread类与线程的创建

使用Thread子类 和 Thread类

子类的好处 :可以在子类中增加新的成员变量,使线程具有某种属性,也可以新增新的方法,使线程具有某种功能。 但是java不支持多继承,Thread的子类不能再扩展其他的类。
使用Thread类 :
通常使用的构造方法是Thread(Runnable target)。该构造方法的参数是一个Runnable类型的接口,所以必须向构造方法的参数传递一个实现Runnable接口的实例(称为创建线程的目标对象),当线程调用start()方法后,一旦轮到它享用CPU资源的时候,目标对象就会自动调用run()方法。
我们知道线程间可以共享相同的内存单元(包括代码与数据),并利用这些共享单元来实现数据的交换,实时通信与必要的同步操作。因此使用同一个目标对象的线程,目标i对象的成员变量自然就是线程共享的数据单元。因此,使用Runnable接口比Thread的子类更具有灵活性。

public class MyClass {
    public static void main(String[] args) {
        House mHouse = new House();
        mHouse.setWaterAmout(10);
        Thread dog,cat;
        dog = new Thread(mHouse);
        cat = new Thread(mHouse);
        dog.setName("狗");
        cat.setName("猫");
        dog.start();
        cat.start();
    }
}
class House implements Runnable{
    int waterAmout;
    public void setWaterAmout(int m){
        waterAmout = m;
    }
    @Override
    public void run() {
        boolean i = true;
        while (i){
            String name = Thread.currentThread().getName();
            if(name.equals("狗")){
                System.out.println(name+"喝水");
                waterAmout = waterAmout - 2;
            }else if(name.equals("猫")){
                System.out.println(name+"喝水");
                waterAmout = waterAmout - 1;
            }else {
                System.out.print("剩下"+waterAmout);
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            if (waterAmout<=0){
                i = false;
            }
        }
    }
}

注意 :wile不要一直为真,否则会卡死
如果输出出现乱码,不要慌,在build.gradle中加入

tasks.withType(JavaCompile) {
    options.encoding = "UTF-8"
}

目标对象与线程的关系

1.目标对象与线程完全解耦

正如上述的例子,House类并没有组合cat 和dog线程的对象(完全解耦),在这种情况下,目标对象经常需要通过获得线程的名字,
String name = Thread.currentThread().getName();
以便确定是哪个线程正在占用cpu的资源。

2.目标对象组合线程(弱耦合)

目标对象可以组合线程,即将线程作为自己的成员(弱耦合),比如让cat 和 dog在House中。
T和read t = Thread.currentThread();
来确定是哪个线程正在占用cpu资源。

public class MyClass {
    public static void main(String[] args) {
        House mHouse = new House();
        mHouse.setWaterAmout(10);
        mHouse.cat.start();
        mHouse.dog.start();
    }
}
class House implements Runnable{
    int waterAmout;
    Thread cat,dog;
    House(){
        cat = new Thread(this);
        dog = new Thread(this);
    }
    public void setWaterAmout(int m){
        waterAmout = m;
    }
    @Override
    public void run() {
        boolean i = true;
        while (i){
            Thread t= Thread.currentThread();
            if(t== dog){
                System.out.println("狗喝水");
                waterAmout = waterAmout - 2;
            }else if(t == cat){
                System.out.println("猫喝水");
                waterAmout = waterAmout - 1;
            }else {
                System.out.print("剩下"+waterAmout);
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            if (waterAmout<=0){
                i = false;
            }
        }
    }
}

线程的常用方法

(1)start():调用该方法将启动线程,使之从新建状态进入就绪队列排队,一旦轮到他来享用CPU资源时,就可以脱离创建它的线程独立开始自己的生命周期。值得注意的是,线程调用start()方法后就不必再让线程调用start()方法。
(2)run() :Thread的run方法和Runnable的run方法的功能和作用相同,都用来定义线程对象被调度之后所执行的操作。
(3)sleep(int millsecond)
(4)isAlive() :线程处于新建状态时,线程调用isAlive()方法返回false.当线程调用start()方法,并占有CPU资源后,该线程的run()方法结束之前,线程调用isAlive()方法返回true.
需要注意的是:一个已经运行的线程在没有进入死亡状态时,不要再给线程分配实体,由于线程只能引用最后分配的实体,先前的实体就会成为“垃圾”,并且不会被垃圾回收机制收集掉。

Thread mThread = new Thread(target);
mThread.start();

如果线程thread占有CPU资源进入了运行状态,这时再执行
tread = new Thread(target);,那么先前的实体就会成为垃圾,并且不会被垃圾收集器收集掉。
(5)currentThread()
currentThread()方法是Thread类中的类方法,可以用类名调用,该方法返回的是当前正在使用的CPU资源的线程。
(6)interrupt():
interrupt()用来“吵醒”休眠的线程。当一个线程处于休眠状态时,一个占有CPU资源的线程可以让休眠的线程调用interrupt()方法“吵醒”自己。比如:线程a正在占用CPU资源,可以在a中用线程b.interrupt(),唤醒线程b。

线程同步

所谓线程同步就是若干个线程都需要使用一个synchronized(同步)修饰方法。多个线程调用synchronized方法必须遵守同步机制。
线程同步机制:当一个线程A使用synchronized方法时,其他线程想使用这个synchronized方法时必须等待,直到线程A使用完该synchronized方法。

线程联合

一个线程A在占有CPU期间,可以让其他线程调用jion()和本线程联合。A在运行期间联合了B,如果线程A在占有CPU资源期间一旦联合的线程B,那么线程A将立刻中断执行,一直等到它联合的线程B执行完毕,A线程再重新排队等待CPU资源,以便恢复执行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值