• Java线程


    线程对象实现

    一、继承Thread类

    创建线程的步骤:
      1、定义一个类继承Thread。
      2、重写run方法。
      3、创建子类对象,就是创建线程对象。
      4、调用start方法,开启线程并让线程执行,同时还会告诉jvm去调用run方法。

    public class MyThread extends Thread {
        @Override
        public void run() {
            for (int i = 0; i < 100; i++) {
                System.out.println(getName() + ":" + i);
            }
        }
    }
    MyThread
    /*
     * 多线程的实现方式1
     * String getName()      返回该线程的名称。 
     * void   setName(String name) 改变线程名称,使之与参数 name 相同。
     */
    public class ThreadDemo {
        public static void main(String[] args) {
            MyThread mt = new MyThread();
            mt.setName("张三");
            mt.start();
            
            MyThread mt2 = new MyThread();
            mt2.setName("李四");
            mt2.start();
        }
    }
    ThreadDemo

    二、实现Runnable接口

    创建线程的另一种方法是声明实现 Runnable 接口的类。该类然后实现 run 方法。然后创建Runnable的子类对象,传入到某个线程的构造方法中,开启线程。

    Runnable接口用来指定每个线程要执行的任务。包含了一个 run 的无参数抽象方法,需要由接口实现类重写该方法。

    创建线程的步骤:
      1、定义类实现Runnable接口。
      2、覆盖接口中的run方法。
      3、创建Thread类的对象。
      4、将Runnable接口的子类对象作为参数传递给Thread类的构造函数。
      5、调用Thread类的start方法开启线程。

    public class MyThread2 implements Runnable {
        int num;
    
        public MyThread2(int num) {
            this.num = num;
        }
    
        @Override
        public void run() {
            for (int i = 0; i < 100; i++) {
                System.out.println(Thread.currentThread().getName() + ":" + i + " - " + num);
            }
        }
    }
    MyThread2
    public class ThreadDemo2 {
        public static void main(String[] args) {
            //创建线程实例
            MyThread2 mt = new MyThread2(100);
            Thread t = new Thread(mt);
            t.setName("张三");
            t.start();
    
            //创建线程实例
            //Thread t2 = new Thread(mt);
            MyThread2 mt2 = new MyThread2(200);
            Thread t2 = new Thread(mt2);
            t2.setName("李四");
            t2.start();
        }
    }
    ThreadDemo2

    多线程安全问题采用加锁解决。


    线程状态转换

    Java 语言定义了5种线程状态,在某一时刻,一个线程只能有其中的一种状态,这5种状态分别如下:

    新建(New):创建后尚未启动的线程处于这种状态。

    运行(Runable):Runable 包括了操作系统线程状态中的 Running 和 Ready,也就是处于此状态的线程有可能正在执行,也有可能正在等待着 CPU 为它分配执行时间。

    无限期等待(Waiting):处于这种状态的线程不会被分配 CPU 执行时间,它们要等待被其他线程显式地唤醒。 以下方法会让线程陷入无限期的等待状态:

    • 没有设置 Timeout 参数的 Object.wait() 方法。
    • 没有设置 Timeout 参数的 Thread.join() 方法。
    • LockSupport.park() 方法。

    限期等待(Timed Waiting):处于这种状态的线程也不会被分配 CPU 执行时间,不过无须等待被其他线程显式地唤醒,在一定时间之后它们会由系统自动唤醒。 以下方法会让线程进入限期等待状态:

    • Thread.sleep() 方法。
    • 设置了 Timeout 参数的 Object.wait() 方法。
    • 设置了 Timeout 参数的 Thread.join() 方法。
    • LockSupport.parkNanos() 方法。
    • LockSupport.parkUntil() 方法。

    阻塞(Blocked):线程被阻塞了,“阻塞状态”与“等待状态”的区别是:“阻塞状态”在等待着获取到一个排他锁,这个事件将在另外一个线程放弃这个锁的时候发生;而“等待状态”则是在等待一段时间,或者唤醒动作的发生。 在程序等待进入同步区域的时候,线程将进入这种状态。

    结束(Terminated):已终止线程的线程状态,线程已经结束执行。上述5种状态在遇到特定事件发生的时候将会互相转换,它们的转换关系如下图。

     注意:

    • wait()方法会释放CPU执行权 和 占有的锁。
    • sleep(long)方法仅释放CPU使用权,锁仍然占用;线程被放入超时等待队列,与yield相比,它会使线程较长时间得不到运行。
    • yield()方法仅释放CPU执行权,锁仍然占用,线程会被放入就绪队列,会在短时间内再次执行。
    • wait和notify必须配套使用,即必须使用同一把锁调用。
    • wait和notify必须放在一个同步块中。
    • 调用wait和notify的对象必须是他们所处同步块的锁对象。

    Java 线程在JDK 1.2后,线程模型变为基于操作系统原生线程模型来实现。 操作系统支持怎样的线程模型,决定了Java虚拟机的线程是怎样映射。线程模型只对线程的并发规模和操作成本产生影响。

    对于 Sun JDK 来说,它的 Windows 版与 Linux 版都是使用一对一的线程模型实现的,一条 Java 线程就映射到一条轻量级进程之中,因为 Windows 和 Linux 系统提供的线程模型就是一对一的。

  • 相关阅读:
    需要了解的项目
    vmware安装问题:Microsoft Runtime DLL安装程序未能完成安装
    rabbitmqctl 报错
    RabbitMQ快速入门python教程
    RabbitMQ消息队基本概念
    Windows RabbitMQ 添加用户、设置角色和权限 (包含无法添加的错误处理)
    转:Window10下RabbitMQ安装图文教程
    Windows下RabbitMQ安装及入门
    crontab 详细用法 定时任务
    转 RabbitMQ
  • 原文地址:https://www.cnblogs.com/boomoom/p/10141063.html
Copyright © 2020-2023  润新知