java高级特性——多线程相关概念及案例

一.进程与线程的概念

进程

1.当一个程序被运行,就开启了一个进程, 比如启动了qq,word

2.程序由指令和数据组成,指令要运行,数据要加载,指令被cpu加载运行,数据被加载到内存,     指令运行时可由cpu调度硬盘、网络等设备

线程

1.CPU调度和分派的基本单位

2.执行运算的最小单元,可完成一个独立的顺序控制流程

3.如果在一个进程中同时运行了多个线程,用来完成不同的工作,则称为多线程

4.多个线程交替占用CPU资源,并非真正的并行执行

主线程

main()方法即为主线程入口,是产生其他子线程的线程

main()方法必须最后完成执行。因为它执行各种关闭动作

public class MainThread {
    public static void main(String[] args) {
        //获取当前的线程对象
        Thread thread=Thread.currentThread();
        System.out.println("当前线程名称是:"+thread.getName());
        thread.setName("New main");
        System.out.println("当前线程名称是:"+thread.getName());

    }
}

二.java中创建线程的方式

1.扩展java.lang.Thread类

这里继承Thread类的方法是比较常用的一种,如果说你只是想起一条线程。没有什么其它特殊的要求,那么可以使用Thread,下面来看一个简单的实例:

//创建并启动线程
public class MyThread extends Thread{
    public void run(){
        for (int i = 1; i <= 100; i++) {
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
    }

}


public class TestThread {
    public static void main(String[] args) {
        //创建线程对象并启动
        MyThread myThread=new MyThread();
        MyThread myThread2=new MyThread();
        //启动线程
        myThread.start();
        myThread2.start();
        //是否可以调用run()方法启动呢?
//        myThread.run();//只有主线程一个执行路径;依次调用了两次run()方法
//        myThread2.run();//run()方法被当成main()方法中一个普通方法执行,失去了线程的意义



由此可以看出,所谓的多线程其实是多个线程交替执行,并不是真正的并行;

线程每次执行的时常由CPU分配的时间片长度决定;

不可以直接调用run()方法启动线程:因为run()方法会被当成main()方法中一个普通方法执行,失去了线程的意义。如下图所示

2.实现java.lang.Runnable接口

Thread2类通过实现Runnable接口,使得该类有了多线程类的特征。run()方法是多线程程序的一个约定。所有的多线程代码都在run方法里面。Thread类实际上也是实现了Runnable接口的类。
在启动的多线程的时候,需要先通过Thread类的构造方法Thread(Runnable target) 构造出对象,然后调用Thread对象的start()方法来运行多线程代码。
实际上所有的多线程代码都是通过运行Thread的start()方法来运行的。因此,不管是扩展Thread类还是实现Runnable接口来实现多线程,最终还是通过Thread的对象的API来控制线程的。

public class MyThread2 implements Runnable{
    public void run(){
        for (int i = 1; i <= 100; i++) {
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
    }

}




public class TestThread2 {
    public static void main(String[] args) {
        //创建线程对象
        Runnable runnable=new MyThread2();//多态,父类引用指向子类对象
        Thread thread=new Thread(runnable,"mythread1");
        Thread thread2=new Thread(runnable,"mythread2");
        //线程调度:设置线程优先级
        thread2.setPriority(10);
        thread.setPriority(1);

        //启动线程
        thread.start();
        thread2.start();
    }

}

 3.Thread和Runnable的区别

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

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

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

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

4):线程池只能放入实现Runable或callable类线程,不能直接放入继承Thread的类
 

三.线程中状态转换

1、新建状态(New):新创建了一个线程对象。
2、就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权。
3、运行状态(Running):就绪状态的线程获取了CPU,执行程序代码。
4、阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:
(一)、等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。(wait会释放持有的锁)
(二)、同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。
(三)、其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。(注意,sleep是不会释放持有的锁)
5、死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。
 

public class MyThread3 implements Runnable {
    public void run(){

        System.out.println("线程正在运行!处于运行状态!");

        try {
            //线程休眠5000ms
            System.out.println("线程开始休眠,处于阻塞状态!");
            Thread.sleep(5000);
            System.out.println("线程休眠结束,阻塞状态结束,再次进入就绪状态!");
        } catch (InterruptedException e) {
            e.printStackTrace();
            System.out.println("线程中断!");
        }


    }

}




public class TestThread3 {
    public static void main(String[] args) {
        Runnable runnable = new MyThread3();
        Thread t=new Thread(runnable,"线程状态1");
        System.out.println("线程处于创建状态!");
        t.start();
        System.out.println("线程就绪!");
    }
}

四.线程调度

1、调整线程优先级:

Java线程有优先级,优先级高的线程会获得较多的运行机会。
 
Java线程的优先级用整数表示,取值范围是1~10,Thread类有以下三个静态常量:
static int MAX_PRIORIT——线程可以具有的最高优先级,取值为10。
static int MIN_PRIORITY—— 线程可以具有的最低优先级,取值为1。
static int NORM_PRIORITY——分配给线程的默认优先级,取值为5。
 

public class TestThread2 {
    public static void main(String[] args) {
        //创建线程对象
        Runnable runnable=new MyThread2();//多态,父类引用指向子类对象
        Thread thread=new Thread(runnable,"mythread1");
        Thread thread2=new Thread(runnable,"mythread2");
        //线程调度:设置线程优先级
        thread2.setPriority(10);
        thread.setPriority(1);

        //启动线程
        thread.start();
        thread2.start();
    }

}

2、线程睡眠:

Thread.sleep(long millis)方法,使线程转到阻塞状态。millis参数设定睡眠的时间,以毫秒为单位。当睡眠结束后,就转为就绪(Runnable)状态。sleep()平台移植性好。

3、线程等待:Object类中的wait()方法,导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 唤醒方法。这个两个唤醒方法也是Object类中的方法,行为等价于调用 wait(0) 一样。

public class Wait {
    public static void bySec(long s){  //s:休眠时间次数
        for (long i = 1; i <= s; i++) {
            System.out.println(i+"秒");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
  }

    public static void main(String[] args) {
        System.out.println("********线程开始休眠********");
        Wait.bySec(5);
        System.out.println("********线程休眠结束********");
    }

}

 

4、线程让步:

Thread.yield() 方法,暂停当前正在执行的线程对象,把执行机会让给相同或者更高优先级的线程。 允许其他具有相同优先级的线程获得运行机会,该线程处于就绪状态,而不是阻塞状态,只是提供一种可能,但是不能保证一定产生礼让!!!!

public class MyThreadTest2 implements Runnable {
    @Override
    public void run() {
        for (int i = 1; i <= 4; i++) {
            System.out.println(Thread.currentThread().getName()+":"+i);
            if(i==3){
                //线程礼让,线程调度:yield()
                System.out.println("线程礼让:");
                Thread.yield();
            }
        }
    }
}





public class Test2 {
    public static void main(String[] args) {
        //创建两个线程对象
        Runnable runnable=new MyThreadTest2();
        Thread t1=new Thread(runnable,"线程A");
        Thread t2=new Thread(runnable,"线程B");
        t1.start();
        t2.start();
    }
}

5、线程加入:

join()方法,等待其他线程终止。在当前线程中调用另一个线程的join()方法,则当前线程转入阻塞状态,直到另一个进程运行结束,当前线程再由阻塞转为就绪状态。

public class Test {
    public static void main(String[] args) {
        //创建子线程对象t
        Runnable runnable=new MyThreadTest();
        Thread t=new Thread(runnable,"myThread");
        t.start();


        //主线程main做的事情
        for (int i = 1; i <= 20; i++) {
            System.out.println(Thread.currentThread().getName()+":"+i);
            //当i=5时,强制把t线程加入执行
            //线程调度:join()---等待t线程执行结束后,main主线程再继续执行
            if(i ==5){
                try {
                    t.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        }
    }
}



public class MyThreadTest implements Runnable{
    public void run(){
        for (int i = 1; i <= 30; i++) {
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
    }

}


猜你喜欢

转载自blog.csdn.net/kkkyzp/article/details/121385803