线程的概念和使用(创建)

一:基本概念

1.程序,进程,线程的理解

  1. 程序(program)是为完成指定任务,用某种语言编写的一组指令集合.指一段静态的代码.
  2. 进程(process)是正在运行的一个程序.是一个动态的过程.
  3. 线程(thread)是一个程序内部的一条执行路径.

2.单核CPU,多核CPU的理解

  1. 单核CPU,实质是一种假的多线程,在一个时间单元内,也只能执行一个线程的任务.
  2. 多核CPU是多线程,每个核单独执行一个线程的任务.
  3. 一个java应用程序java.exe,至少有三个线程:main()主线程,gc()垃圾回收线程,异常处理线程.

3.并行与并发

  1. 并行:多个CPU同时执行多个任务.(多个人同时做不同的事)
  2. 并发:一个CPU(采用时间片)同时执行多个任务.(多个人做同一件事)

4.多线程优点

  1. 提高应用程序的响应.
  2. 提高CPU的利用率
  3. 改善程序结构

5.何时需要多线程

  1. 程序需要同时执行两个或多个任务.
  2. 程序需要实现一些需要等待的任务.
  3. 需要一些后台运行的程序时.

二:线程的创建和使用

JVM允许程序运行多个线程,通过java.lang.Thread类体现.JDK1.5之前有两种方式创建线程: 继承Thread类 和 实现Runnable接口.

1.继承Thread类

  1. Thread类特性

    1. 每个线程都是通过某个特定Thread对象的run()方法完成操作的,常把run()方法的主体称为线程体.
    2. 通过Thread对象的start()方法启动线程,不是直接调用run()方法
  2. Thread类构造器

    1. Thread(): 创建Thread对象
    2. Thread(String threadname): 创建线程并指定线程实例名
    3. Thread(Runnable target): 创出线程的目标对象,它实现了Runnable接口的run()
    4. Thread(Runnable target, String name): 创建新的Thread对象
  3. 流程

    1. 继承Thread
    2. 重写Thread中的run()
    3. 创建线程对象
    4. 调用对象的start(): 启动线程,调用run()
  4. 示例

    //1. 创建一个继承于Thread类的子类
    class MyThread extends Thread {
        public MyThread(){}
        public MyThread(String name){ super(name); }
    
        //2. 重写Thread类的run()
        @Override
        public void run() {
            for (int i = 0; i < 100; i++) {
                if (i % 2 == 0) {
                    /*public Thread() {
                        init(null, null, "Thread-" + nextThreadNum(), 0);
                    }*/
                    System.out.println(Thread.currentThread().getName() + ":" + i);
                }
            }
        }
    }
    
    public class ThreadTest {
        public static void main(String[] args) {
            //3. 创建Thread类的子类的对象
    //        MyThread t1 = new MyThread();
            MyThread t1 = new MyThread("分线程");
            //设置线程名称
    //        t1.setName("线程一");
    
            //4.通过此对象调用start():①启动当前线程 ② 调用当前线程的run()
            t1.start();
    
            //问题一:我们不能通过直接调用run()的方式启动线程。
    //        t1.run();
            //问题二:再启动一个线程,遍历100以内的偶数。不可以还让已经start()的线程去执行。
            /*if (threadStatus != 0)
                throw new IllegalThreadStateException();*/
    //        t1.start();       // java.lang.IllegalThreadStateException
    
            //我们需要重新创建一个线程的对象
            MyThread t2 = new MyThread();
            t2.start();
            Thread.currentThread().setName("主线程");
    
            //如下操作仍然是在main线程中执行的。
            for (int i = 0; i < 100; i++) {
                if (i % 2 == 0) {
                    System.out.println(Thread.currentThread().getName() + ":" + i);
                }
            }
        }
    }
    
  5. 注意点

    1. 对象调用run()方法,没有启动多线程模式,
    2. run()方法由JVM掉用,什么时候,执行过程都由CPU调度决定.
    3. 启动多线程,必须调用start()方法.
    4. 一个线程对象不能重复调用start()方法,否则发生 “线程状态不符” 异常

2.实现Runnable接口

  1. 流程

    1. 实现Runnable接口.
    2. 重写Runnable接口中的run()方法.
    3. 通过Thread(Runnable target)构造器创建线程对象.
    4. 调用start()方法: 开启线程,调用Runnable子类接口的run()方法.
  2. 示例

    //1. 创建一个实现了Runnable接口的类
    class MyThread2 implements Runnable{
        //2. 实现类去实现Runnable中的抽象方法:run()
        @Override
        public void run() {
            for (int i = 0; i <= 100 ; i++) {
                if (i % 2 == 0){
                    System.out.println(Thread.currentThread().getName()+":"+i);
                }
            }
        }
    }
    
    public class ThreadTest2 {
        public static void main(String[] args) {
            //3. 创建实现类的对象
            MyThread2 r1 = new MyThread2();
            //4. 将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
            Thread t1 = new Thread(r1);
            t1.setName("线程1");
            //5. 通过Thread类的对象调用start():① 启动线程 ②调用当前线程的run()
            // -->调用了Runnable类型的target的run()
            t1.start();
    
            //再启动一个线程,遍历100以内的偶数
            Thread t2 = new Thread(r1);
            t2.setName("线程2");
            t2.start();
        }
    }
    

3.两种方式的联系与区别

public class Thread extends Object implements Runnable

  1. 联系: 都需要重写run()方法,将线程要执行的逻辑都声明在run()中
  2. 实现Runnable接口方式的好处
    1. 避免了单继承的局限性
    2. 多个线程可以共享同一个接口实现类的对象,适合处理多个线程有共享数据的情况

三:Thread类的相关方法

  1. void start(): 启动当前线程,并执行当前线程的run()方法
  2. run(): 被CPU调度时执行的操作,将创建的线程要执行的操作声明在此方法中
  3. String getName(): 返回线程的名称
  4. void setName(String name): 设置线程的名称
  5. static Thread currentThread(): 返回执行当前代码的线程. 在Thread子类中指this, 通常用于主线程和Runnable实现类.
  6. static void yield(): 释放当前cpu的执行权
  7. join(): 在线程a中调用线程b的join(),此时线程a就进入阻塞状态,直到线程b完全执行完以后,线程a才结束阻塞状态
  8. static void sleep(long millitime): 让当前线程“睡眠”指定的millitime毫秒。在指定的millitime毫秒时间内,当前线程是阻塞状态
  9. boolean isAlive(): 判断当前线程是否存活

四:线程的优先级及分类

  1. 调用策略: 时间片(单元时间内做任务切换) 或 抢占式(高优先级的线程抢占CPU)
  2. 调度方法: 同优先级线程组成先进先出队列(先到先服务),使用时间片策略; 对高优先级,使用抢占式策略
  3. 线程优先级
    1. MAX_PRIORITY: 10; MIN_PRIORITY: 1; NORM_PRIORITY: 5;(默认优先级)
    2. getPriority(): 返回线程等级值; setPriority(int newPriority): 设置线程等级值
    3. 说明: 线程创建时继承父线程的优先级; 低优先级只是获得调度的概率低,并不一定在高优先级线程之后才被调用
  4. 线程分类
    1. 分为守护线程 和 用户线程.
    2. 守护线程是用来服务用户线程的,在start()方法前调用thread.setDaemon(true)可以把一个用户线程变为一个守护线程.
    3. java垃圾回收就是一个守护线程.若JVM中都是守护线程,当前JVM将退出.

示例:

class HelloThread extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            if(i % 2 == 0){

//                try {
//                    sleep(10);
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }

                System.out.println(Thread.currentThread().getName() + ":" + Thread.currentThread().getPriority() + ":" + i);
            }

//            if(i % 20 == 0){
//                yield();
//            }
        }
    }

    public HelloThread(String name){
        super(name);
    }
}


public class ThreadMethodTest {
    public static void main(String[] args) {
        HelloThread h1 = new HelloThread("Thread:1");

//        h1.setName("线程一");
        //设置分线程的优先级
        h1.setPriority(Thread.MAX_PRIORITY);
        h1.start();

        //给主线程命名
        Thread.currentThread().setName("主线程");
        Thread.currentThread().setPriority(Thread.MIN_PRIORITY);

        for (int i = 0; i < 100; i++) {
            if(i % 2 == 0){
                System.out.println(Thread.currentThread().getName() + ":" + Thread.currentThread().getPriority() + ":" + i);
            }

//            if(i == 20){
//                try {
//                    h1.join();
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
//            }
        }

//        System.out.println(h1.isAlive());
    }
}

五:示例

/**
 * 示例:创建两个分线程,其中一个线程遍历100以内的偶数,另一个线程遍历100以内的奇数
 *
 * @author zlg
 * @create 2019-10-25 1:56
 */
public class ThreadDemo {
    public static void main(String[] args) {
//        MyThread1 m1 = new MyThread1();
//        MyThread3 m2 = new MyThread3();
//        m1.start();
//        m3.start();

      	// 方式二:采用匿名内部类
        //创建Thread类的匿名子类的方式:遍历偶数
        new Thread(){
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    if(i % 2 == 0){
                        System.out.println(Thread.currentThread().getName() + ":" + i);
                    }
                }
            }
        }.start();

		//创建Thread类的匿名子类的方式:遍历奇数
        new Thread(){
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    if(i % 2 != 0){
                        System.out.println(Thread.currentThread().getName() + ":" + i);
                    }
                }
            }
        }.start();

    }
}

//方式一:采用两个类分别执行不同任务
// 遍历100以内偶数
class MyThread1 extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            if(i % 2 == 0){
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
        }
    }
}

// 遍历100以内奇数
class MyThread3 extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            if(i % 2 != 0){
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
        }
    }
}
发布了91 篇原创文章 · 获赞 2 · 访问量 2425

猜你喜欢

转载自blog.csdn.net/zhixingwu/article/details/103226104