【Java】创建线程

下面笔记来源尚硅谷,仅供学习。

基本流程

  1. 定义一个类,继承Thread
  2. 重写run方法,在run方法中设置线程任务(所谓的线程任务指的是此线程要干的具体的事儿,具体执行的代码)
  3. 创建自定义线程类的对象
  4. 调用自定义线程类对象中的start方法,开启线程,jvm自动调用run方法

方法一:继承类

public class Test01 {
    public static void main(String[] args) {
        //创建线程对象
        MyThread t1 = new MyThread();
        //调用start方法,开启线程,jvm自动调用run方法
        t1.start();

        for (int i = 0; i < 10; i++) {
            System.out.println("main线程..........执行了"+i);
        }
    }
}
public class MyThread extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("MyThread...执行了"+i);
        }
    }
}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Thread 类中的方法

void start() -> 开启线程,jvm自动调用run方法

void run()  -> 设置线程任务,这个run方法是Thread重写的接口Runnable中的run方法

String getName()  -> 获取线程名字

void setName(String name) -> 给线程设置名字

static Thread currentThread() -> 获取正在执行的线程对象(此方法在哪个线程中使用,获取的就是哪个线程对象)   

static void sleep(long millis)->线程睡眠,超时后自动醒来继续执行,传递的是毫秒值 

void setPriority(int newPriority)   -> 设置线程优先级,优先级越高的线程,抢到CPU使用权的几率越大,但是不是每次都先抢到
    
int getPriority()  -> 获取线程优先级 默认为5 最小1 最大10
    
void setDaemon(boolean on) 
//设置为守护线程,当非守护线程执行完毕,守护线程就要结束
//但是守护线程也不是立马结束,会延迟一小段时间结束
    
static void yield() -> 礼让线程,让当前线程让出CPU使用权
   
void join() -> 插入线程或者叫做插队线程    
public class MyThread extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            //线程睡眠
            try {
                Thread.sleep(1000L);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println(Thread.currentThread().getName()+"...执行了"+i);
        }
    }
}

public class Test01 {
    public static void main(String[] args) throws InterruptedException {
        //创建线程对象
        MyThread t1 = new MyThread();

        //给线程设置名字
        t1.setName("金莲");

        //调用start方法,开启线程,jvm自动调用run方法
        t1.start();

        for (int i = 0; i < 10; i++) {
            Thread.sleep(1000L);
            System.out.println(Thread.currentThread().getName()+"线程..........执行了"+i);
        }
    }
}

问题:为啥在重写的run方法中有异常只能try,不能throws?

原因:继承的Thread中的run方法没有抛异常,所以在子类中重写完run方法之后就不能抛,只能try

线程优先级

public class MyThread1 extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName()+"执行了......"+i);
        }
    }
}
public class Test01 {
    public static void main(String[] args) {
        MyThread1 t1 = new MyThread1();
        t1.setName("金莲");

        MyThread1 t2 = new MyThread1();
        t2.setName("阿庆");

        /*
           获取两个线程的优先级
           MIN_PRIORITY = 1 最小优先级 1
           NORM_PRIORITY = 5 默认优先级 5
           MAX_PRIORITY = 10 最大优先级 10
         */
        //System.out.println(t1.getPriority());
        //System.out.println(t2.getPriority());

        //设置优先级
        t1.setPriority(1);
        t2.setPriority(10);

        t1.start();
        t2.start();
    }
}

守护线程

public class Test01 {
    public static void main(String[] args) {
        MyThread1 t1 = new MyThread1();
        t1.setName("金莲");

        MyThread2 t2 = new MyThread2();
        t2.setName("阿庆");

        //将t2设置成守护线程
        t2.setDaemon(true);

        t1.start();
        t2.start();
    }
}

public class MyThread1 extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName()+"执行了......"+i);
        }
    }
}
public class MyThread2 extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName()+"执行了..."+i);
        }
    }
}

比如QQ聊天,聊天的同时可以传输文件,可以把传输文件的过程设置为守护线程

礼让线程

只是尽可能的礼让

public class Test01 {
    public static void main(String[] args) {
        MyThread1 t1 = new MyThread1();
        t1.setName("金莲");

        MyThread1 t2 = new MyThread1();
        t2.setName("阿庆");


        t1.start();
        t2.start();
    }
}
public class MyThread1 extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName()+"执行了......"+i);
            Thread.yield();
        }
    }
}

插入线程

就是插队

public class MyThread1 extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName()+"执行了......"+i);
        }
    }
}
public class Test01 {
    public static void main(String[] args) throws InterruptedException {
        MyThread1 t1 = new MyThread1();
        t1.setName("金莲");
        t1.start();

        /*
          表示把t1插入到当前线程之前,t1要插到main线程之前,所以当前线程就是main线程
         */
        t1.join();

        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName()+"执行了......"+i);
        }
    }
}

方法二:实现接口

基本过程:

  1. 创建类,实现Runnable接口
  2. 重写run方法,设置线程任务
  3. 利用Thread类的构造方法:Thread(Runnable target),创建Thread对象(线程对象),将自定义的接口实现类当参数传递到Thread构造函数中 -> 这一步是让我们自己定义的类成为一个真正的线程类对象
  4. 调用Thread中的start方法,开启线程,jvm自动调用run方法
public class Test01 {
    public static void main(String[] args) {
        MyRunnable myRunnable = new MyRunnable();

        /*
           Thread(Runnable target)
         */
        Thread t1 = new Thread(myRunnable);
        //调用Thread中的start方法,开启线程
        t1.start();

        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName()+"...执行了"+i);
        }
    }
}
public class MyRunnable implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName()+"...执行了"+i);
        }
    }
}

还可以使用匿名内部类创建多线程:

1.new 接口/抽象类(){
      重写方法
  }.重写的方法();

2.接口名/类名 对象名 = new 接口/抽象类(){
      重写方法
  }
 对象名.重写的方法();
public class Test02 {
    public static void main(String[] args) {
        /*
          Thread(Runnable r)
          Thread(Runnable target, String name) :name指的是给线程设置名字
         */

        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    System.out.println(Thread.currentThread().getName()+"...执行了"+i);
                }
            }
        },"阿庆").start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    System.out.println(Thread.currentThread().getName()+"...执行了"+i);
                }
            }
        },"金莲").start();
    }
}

两种创建方式的区别:

  1. 继承Thread:继承只支持单继承,有继承的局限性
  2. 实现Runnable:没有继承的局限性, MyThread extends Fu implements Runnable

方法三:Callable接口

  1. 概述:Callable<V>是一个接口,类似于Runnable

  2. 方法:

    V call() -> 设置线程任务的,类似于run方法

  3. call方法和run方法的区别:

    • 相同点:都是设置线程任务的
    • 不同点:
      • call方法有返回值,而且有异常可以throws
      • run方法没有返回值,而且有异常不可以throws
  4. 获取call方法返回值: FutureTask<V>

    • FutureTask<V> 实现了一个接口: Future <V>
    • FutureTask<V>中有一个方法: V get()-> 获取call方法的返回值
public class MyCallable implements Callable<String> {

    @Override
    public String call() throws Exception {
        return "...的故事";
    }
}
public class Test {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        MyCallable myCallable = new MyCallable();
        /*
           FutureTask(Callable<V> callable)
         */
        FutureTask<String> futureTask = new FutureTask<>(myCallable);

        //创建Thread对象-> Thread(Runnable target)
        Thread t1 = new Thread(futureTask);
        t1.start();

        //调用get方法获取call方法返回值
        System.out.println(futureTask.get());
    }
}

方法四:线程池

之前来一个线程任务,就需要创建一个线程对象去执行,用完还要销毁线程对象。

如果线程任务多了,就需要频繁创建线程对象和销毁线程对象,这样会耗费内存资源,所以我们就想线程对象能不能循环利用,用的时候直接拿线程对象,用完还回去。

  1. 如何创建线程池对象: 工具类-> Executors

  2. 获取线程池对象:Executors中的静态方法: static ExecutorService newFixedThreadPool(int nThreads)

    • 参数:指定线程池中最多创建的线程对象条数
    • 返回值ExecutorService 是线程池,用来管理线程对象
  3. 执行线程任务: ExecutorService中的方法

    • Future<?> submit(Runnable task) 提交一个Runnable任务用于执行
    • Future<T> submit(Callable<T> task)提交一个Callable任务用于执行
  4. submit方法的返回值: Future接口 -> 用于接收run方法或者call方法返回值的,但是run方法没有返回值,所以可以不用Future接收,执行call方法需要用Future接收。

    Future中有一个方法:V get() 用于获取call方法返回值

  5. ExecutorService中的方法: void shutdown() 启动有序关闭,其中先前提交的任务将被执行,但不会接受任何新任务

public class MyRunnable implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"...执行了");
    }
}
public class Test01 {
    public static void main(String[] args) {
        //创建线程池对象
        ExecutorService es = Executors.newFixedThreadPool(2);
        es.submit(new MyRunnable());
        es.submit(new MyRunnable());
        es.submit(new MyRunnable());

        //es.shutdown();//关闭线程池对象
    }
}
public class MyCallable implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        return 1;
    }
}
public class Test02 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService es = Executors.newFixedThreadPool(2);
        Future<Integer> future = es.submit(new MyCallable());
        System.out.println(future.get());
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秀秀_heo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值