Java多线程之线程的创建

一、三种创建方式

基于什么创建 创建的方式
Thread类 继承Thread
Runnable接口 实现Runnable接口
callable接口 实现callable接口

二、通过Thread类创建

2.1 步骤

  • 自定义线程类继承Thread
  • 重写run()方法,编写线程执行体(当成main()方法用)
  • 创建线程对象,调用start()方法启动线程

2.2 案例

  • 创建两个线程,其中一个线程打印100以内的偶数,另一个线程打印100以内的奇数
//主方法
public class Demo01 {
    public static void main(String[] args) {
        Thread1 thread1 = new Thread1();
        Thread2 thread2 = new Thread2();

        thread1.start();
        thread2.start();
    }
}

//100以内的偶数
class Thread1 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 Thread2 extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            if (i%2!=0){
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
        }
    }
}
  • 也可以使用匿名内部类的方法来实现(线程用过以后就不再用了)
public class Demo02 {
    public static void main(String[] args) {
        //打印0~100内的偶数
        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();
        //打印0~100内的奇数
        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张(注意票数应该是静态变量,否则就是没创建一个对象,该对象就有100张票)
public class Test {
    public static void main(String[] args) {
        Window w1 = new Window("窗口 1 ");
        Window w2 = new Window("窗口 2 ");
        Window w3 = new Window("窗口 3 ");

        w1.start();
        w2.start();
        w3.start();
    }
}

class Window extends Thread{
    //这里票的数量应该是静态变量,否则每个对象创建后都有100张票,而不是总共100张票
    private static int tickets = 100;

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

    @Override
    public void run() {
        while (tickets > 0){
            tickets--;
            System.out.println(getName() + "卖出了一张票,剩余票数:" + tickets);
        }
    }
}
  • 注意:这里存在一个线程安全问题未解决,后面将会讲到。如下图所示,刚开始三个线程启动的时候,读取的票数都是100张。

2.3 注意的问题

  • start()方法的作用:通过调用自己写的线程类对象的start()方法,来启动该线程,并调用该线程的run()方法
  • 不能通过直接调用run()方法的方式启动线程
  • 不可以让已经start()的线程再次star()来同时跑两个线程。可以通过新建一个该线程类的对象,然后在对新建的对象start()

三、Thread类中常用的方法

  • start()启动当前线程;调用当前线程的run()方法
  • run():通常需要重写Thread类中的此方法,将创建线程需要执行的操作声明在此方法中(当做main()使用)
  • currentThread():静态方法,返回执行当前代码的线程
  • getName():获取当前线程的名字
  • setName(String name):设置当前线程的名字
  • yield():释放当前CPU的执行权(但也有可能下一刻的执行权又回到了当前线程,主控权还是在CPU手上)
  • join():在线程a中调用线程bjoin(),此时线程a就进入阻塞状态,直到线程b完全执行完之后,线程a在结束阻塞状态
  • stop():当执行此方法时,强制结束当前线程(已停用
  • sleep(int millitime):让当前线程“睡眠”指定的millitime毫秒。在指定的millitime毫秒时间内,当前进程是阻塞状态
  • isAlive():判断当前线程是否存活(线程执行完之前都是存活的)

3.1 案例

  • 同样是上面的三个窗口买票的问题,同样是100张票,但使用这种创建方法,tickets可以不使用静态变量

四、通过实现Runnable接口来创建线程

4.1 创建步骤

  • 创建一个实现了Runnable接口的类
  • 实现类去实现Runnable接口中的抽象方法:run()
  • 创建实现类的对象
  • 将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
  • 通过Thread类的对象调用start()
  • 这里的start()首先启动了当前的线程,然后调用了Runnable类型的target的run()

五、继承Thread类和实现Runnable接口两种方式比较

开发中,优先选择实现Runnable接口的方式创建线程

原因:

  • 实现Runnable接口的方式没有类的单继承性的局限性(一个类只能继承一个父类,继承了Thread类就不能在继承其他类了)
  • 实现Runnable接口的方式更适合来处理多个线程之间有共享数据的情况

联系:Thread类本身也实现了Runnable接口

相同点:两种方式都需要重写run()方法,将线程要执行的逻辑声明在run()方法中

六、线程的优先级设置

调度策略

  • 对于同优先级的线程,组成先入先出队列(先到先服务),使用时间片策略
  • 对于高优先级,使用优先调度的抢占式模式

线程的优先级分为1~10十个档,其中:

  • NORM_PRIORITY:5 —— 普通优先级,即默认的优先级
  • MAX_PRIORITY:10 —— 最高优先级
  • MIN_PRIORITY:1 —— 最低优先级
  • getPriority():获取线程的优先级
  • setPriority(int p):设置线程的优先级

注意:高优先级的线程要抢占低优先级线程CPU的执行权。但是只是从概率上来讲,高优先级的线程高概率的情况下被执行。并不意味着只有当高优先级的线程被执行完以后,低优先级的线程才会被执行。

七、总结

线程开启后不一定立即执行,有CPU进行调度(如果只有一个CPU,主线程和创建的线程会交替执行)

到此这篇关于Java多线程之线程的创建的文章就介绍到这了,更多相关Java线程的创建内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java concurrency之共享锁和ReentrantReadWriteLock_动力节点Java学院整理

    ReadWriteLock 和 ReentrantReadWriteLock介绍 ReadWriteLock,顾名思义,是读写锁.它维护了一对相关的锁 - - "读取锁"和"写入锁",一个用于读取操作,另一个用于写入操作. "读取锁"用于只读操作,它是"共享锁",能同时被多个线程获取. "写入锁"用于写入操作,它是"独占锁",写入锁只能被一个线程锁获取. 注意:不能同时存在读取锁和写入锁

  • Java多线程之synchronized关键字的使用

    一.使用在非静态方法上 public synchronized void syzDemo(){ System.out.println(System.currentTimeMillis()); System.out.println("进入synchronized锁:syzDemo"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } 二.使用在静态方法上 publi

  • Java多线程 ReentrantReadWriteLock原理及实例详解

    读写锁ReentrantReadWriteLock概述 读写锁ReentrantReadWriteLock,使用它比ReentrantLock效率更高. 读写锁表示两个锁,一个是读操作相关的锁,称为共享锁:另一个是写操作相关的锁,称为排他锁. 1.读和读之间不互斥,因为读操作不会有线程安全问题 2.写和写之间互斥,避免一个写操作影响另外一个写操作,引发线程安全问题 3.读和写之间互斥,避免读操作的时候写操作修改了内容,引发线程安全问题 多个Thread可以同时进行读取操作,但是同一时刻只允许一个

  • Java多线程之深入理解ReentrantLock

    前言 保证线程安全的方式有很多,比如CAS操作.synchronized.原子类.volatile保证可见性和ReentrantLock等,这篇文章我们主要探讨ReentrantLock的相关内容.本文基于JDK1.8讲述ReentrantLock. 一.可重入锁 所谓可重入锁,即一个线程已经获得了某个锁,当这个线程要再次获取这个锁时,依然可以获取成功,不会发生死锁的情况.synchronized就是一个可重入锁,除此之外,JDK提供的ReentrantLock也是一种可重入锁. 二.Reent

  • Java基础之多线程的三种实现方式

    一.前言 Java多线程实现的三种方式有继承Thread类,实现Runnable接口,使用ExectorService.Callable.Future实现有返回结果的多线程.其中前两种方式线程执行完后都没有返回值,只有最后一种是带返回值的. 二.继承Thread类实现多线程 1.Thread本质上也是实现了Runnable接口的一个实例,它代表一个线程的实例,并且,启动线程的唯一方法就是通过Thread类的start()实例方法. 2.start()方法是一个native方法,它将启动一个新线程

  • Java多线程之哲学家就餐问题详解

    一.题目 教材提供一个哲学家就餐问题的解决方案的框架.本问题要求通过pthreads 互斥锁来实现这个解决方案. 哲学家 首先创建 5 个哲学家,每个用数字 0~4 来标识.每个哲学家作为一个单独的 线程运行. 可使用 Pthreads 创建线程.哲学家在思考和吃饭之间交替.为了模拟这两种活动,请让线程休眠 1 到 3 秒钟.当哲学家想要吃饭时,他调用函数: pickup_forks(int philosopher _number) 其中,philosopher _number 为想吃饭哲学家的

  • Java多线程之Park和Unpark原理

    一.基本使用 它们是 LockSupport 类中的方法 // 暂停当前线程 LockSupport.park(); // 恢复某个线程的运行 LockSupport.unpark(暂停线程对象) 应用:先 park 再 unpark Thread t1 = new Thread(() -> { log.debug("start..."); sleep(1); log.debug("park..."); LockSupport.park(); log.debu

  • Java多线程之ReentrantReadWriteLock源码解析

    一.介绍 1.1 ReentrantReadWriteLock ReentrantReadWriteLock 是一个读写锁,允许多个读或者一个写线程在执行. 内部的 Sync 继承自 AQS,这个 Sync 包含一个共享读锁 ReadLock 和一个独占写锁 WriteLock. 该锁可以设置公平和非公平,默认非公平. 一个持有写锁的线程可以获取读锁.如果该线程先持有写锁,再持有读锁并释放写锁,称为锁降级. WriteLock支持Condition并且与ReentrantLock语义一致,而Re

  • Java多线程之简单模拟售票功能

    一.创建 二.完整代码 package com.ql; import lombok.SneakyThrows; import okhttp3.Call; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; import java.io.IOException; public class Mythread extends Thread { public Mythread(String name)

  • Java多线程之Disruptor入门

    一.Disruptor简介 Disruptor目前是世界上最快的单机消息队列,由英国外汇交易公司LMAX开发,研发的初衷是解决内存队列的延迟问题(在性能测试中发现竟然与I/O操作处于同样的数量级).基于Disruptor开发的系统单线程能支撑每秒600万订单,2010年在QCon演讲后,获得了业界关注.2011年,企业应用软件专家Martin Fowler专门撰写长文介绍.同年它还获得了Oracle官方的Duke大奖.目前,包括Apache Storm.Camel.Log4j 2在内的很多知名项

随机推荐