多线程

1、多线程程序执行是乱序执行的,代码中要调用sleep()方法,来释放cpu资源,让其他线程进入

2、调用start()方法运行线程的时候并不会马上执行代码,使线程进入runable状态(就绪),什么时候运行是系统决定的,看哪一个线程先得到cpu资源

3、run()方法是多线程的一个约定,所有的多线程代码都放在run()方法里

4、实现Runnable接口比继承Thread类所具有的优势:

 ①:适合多个相同的程序代码的线程去处理同一个资源

②:可以避免java中的单继承的限制

③:增加程序的健壮性,代码可以被多个线程共享,代码和数据独立

5、在java中,启动程序,最少产生两个线程,一个是main线程,一个是垃圾回收机制线程

6、线程状态:

  例:1、【创建】下载某个app

         2、【就绪】开通该app的网络、定位权限等

         3、【运行】使用该app

         4、【阻塞】点击'发布动态'按钮,此时又刷新了首页,发布动态的行为就暂阻塞,先刷新了首页,后发布了动态

         5、【死亡】退出app


①创建状态(new):创建一个线程对象

②就绪状态(runable):调用start()方法,使线程进入就绪状态,等待得到cpu资源

③运行状态(running):线程得到cpu资源,开始运行

④阻塞状态(blocked):线程因为某种原因放弃cpu使用权,暂时停止运行,直到线程进入到就绪状态才有机会进入到运行状态

(1)等待阻塞:运行的线程执行wait()方法,jvm将线程放入等待池中

(2)同步阻塞:运行的线程在获取对象的同步锁时,该同步锁被其他线程占用,JVM会把该线程放入锁池中

(3)其他阻塞:运行的线程执行sleep()或者join()方法,或者发出I/O请求,jvm会把该线程设置成阻塞状态,当sleep()超时、join()等待线程时间终止或者超时,I/O请求处理完成,JVM会将该线程重新纳入就绪状态,等待运行

⑤死亡状态:线程运行结束或者其他异常退出run()方法,该线程结束生命周期

7.多线程常用方法:

(1)sleep(long millis):指定该线程执行秒数内的休眠(暂停执行)

(2)join():等待该线程终止,(例:主线程要等待子线程处理的结果,所以不能让主线程在子线程之前结束,子线程.join(),等待该子线程结束)

(3)yield():暂停当前正在执行的线程,让当前线程回到可运行状态,并执行其他线程。目的是相同优先级的线程之间能适当的轮流执行,(先检测当前是否有相同优先级的线程处于可运行状态,如有,把CPU的占有权给它,反之,继续运行原来的线程,所以,yield方法称为‘退让’,把运行机会让给同等优先级的其他线程)

       ① yield()和sleep(long millis)的区别:

       Ⅰ sleep方法使线程进入阻塞状态,在规定的时间内不会运行,yield方法使线程进入可执行状态,有可能在进入到可执行状态后马上又被执行

       Ⅱ sleep方法使线程睡眠一段时间,这个时间是可以控制的,yield方法使当前线程让出CPU资源,但让出的时间是不可设定的

       Ⅲ sleep方法允许较低优先级的线程获取CPU资源,yield方法只允许同级的线程获取CPU资源

(4)setPriority():更改线程的优先级

(5)wait():强迫一个线程等待

8.继承Thread类,重写run方法:

public class Test extends Thread {
    private String name;

    public Test(String name) {
        this.name = name;
    }

    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(name + "運行:" + i);
        }
    }

    public static void main(String[] args) {

        Test thread = new Test("A");

        //sart方法实际执行的是run方法,start方法只是让线程进入可执行状态,什么时候执行是由JVM确定的

        thread.start();

        Test thread2 = new Test("B");
        thread2.start();

    }

}

输出结果:

B運行:0
B運行:1
B運行:2
A運行:0

A運行:1

.................再运行一次程序,结果会不同

9.实现Runable接口

public class Test implements Runnable {
    private String name;

    public Test(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        for (int i = 0; i < 3; i++) {
            System.out.println(name + "運行:" + i);
        }
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        new Thread(new Test("C")).start();
        new Thread(new Test("D")).start();
    }

}

输出结果:

C運行:0
C運行:1
D運行:0
D運行:1
D運行:2
C運行:2
..................再运行一次程序,结果会不同

10.synchronized 同步关键字

1)当两个并发线程(runableA、runableB)访问同一个对象(test)中的synchronized代码块时,在同一时刻只能有一个线程执行,另一个线程阻塞,等当前线程执行完毕后另一个线程才能执行该代码块。

public class Test implements Runnable {

    @Override
    public void run() {
        synchronized (this) {
            for (int i = 0; i < 3; i++) {
                System.out.println(Thread.currentThread().getName() + "運行:" + i);
            }
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        Test test = new Test();
        new Thread(test, "runableA").start();
        new Thread(test, "runableB").start();
    }
}

运行结果【运行多次结果仍一致】:

runableA運行:0
runableA運行:1
runableA運行:2
runableB運行:0
runableB運行:1
runableB運行:2

2)将以上代码中的main方法代码修改为以下

当两个并发线程(runableA、runableB)访问Test的两个对象中的synchronized代码时,两个线程可以同时进行,因为synchronized只锁定对象,每个对象只有一个锁与之关联,以下代码创建了 两个Test类的对象,所以会有两把锁分别锁定Test类的两个对象,而这两把锁互不干扰。

 public static void main(String[] args) {
        new Thread(new Test(), "runableA").start();
        new Thread(new Test(), "runableB").start();

    }

输出结果:

runableB運行:0
runableB運行:1
runableB運行:2
runableA運行:0
runableA運行:1
runableA運行:2

再运行一次:

runableA運行:0
runableA運行:1
runableA運行:2
runableB運行:0
runableB運行:1
runableB運行:2

3)当一个线程访问对象的一个synchronsized(this)同步代码块时,另一个线程仍然可以访问该对象中的非synchronsized(this)同步代码块。

4)synchronsized(object)修饰对象,即给该对象加了锁,当一个线程访问object对象时,其他试图访问object对象的线程将会阻塞,直到该线程访问object对象结束,谁拿到那个锁谁就有执行那块代码的权利。

5)synchronsized修饰一个方法:

  

public synchronsized void methodName(){}

6)synchronsized修饰一个代码块:

public void methodName(){

      synchronsized(this){

         //todo

     }

}

注:synchronsized修饰方法和代码块的作用是等价的,都是锁定了整个方法的内容。

7)synchronsized 关键字不能继承

   虽然synchronsized可以用来修饰方法,但它并不是定义方法的一部分,如果父类定义了synchronsized修饰的公共方法,子类覆盖了该方法,子类中的该方法是默认不同步的,可以通过显示的在子类继承的方法中添加synchronsized修饰,也可以通过在子类的方法中调用父类的同步方法,效果是等同的。

class Person(){

      public synchronsized void method(){}

}


class Student extends Person(){

    public synchronsized void method(){}

}

或者

class Student extends Person(){

    public void method(){

          super.method();

    }

}

8)接口方法不能用synchronsized修饰;构造方法不能使用synchronsized修饰,但是可以在构造方法中使用synchronsized修饰代码块。

9)synchronsized修饰静态方法,静态方法属于类而不属于对象,所以synchronsized修饰的静态方法的使用对象是这个类的所有对象。相当于该类的所有对象用了同一把锁(效果等同synchronized修饰类 即synchronsized(Person.class))。

注:实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制

11.线程数据传递

1)多线程编写程序对线程处理的参数通常可通过构造函数来传入,这样能保证在线程在运行之前该参数就已经传入

public class Test extends Thread {
    private String name;

    public Test(String name) {
        this.name = name;
    }

    public void run() {
        System.out.println("hello:" + name);
    }

    public static void main(String[] args) {
        Thread thread = new Test("Thread1");
        thread.start();
    }
}

2)当有多个参数的时候,放在构造方法中会显得构造方法很冗余,可通过变量(字段)和set方法来传入

public class Test implements Runnable {
    private String name;
    private int age;
    private String school;

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void setSchool(String school) {
        this.school = school;
    }

    public void run() {
        System.out.println("My name is:" + name + ",age:" + age + ",school:" + school);
    }

    public static void main(String[] args) {
        Test thread = new Test();
        thread.setName("TOM");
        thread.setAge(20);
        thread.setSchool("浙大");
        new Thread(thread).start();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值