【线程的基本用法(创建、常见的构造方法、中断、等待、休眠)】

线程创建

  1. 继承Thread
/**
 * 继承Thread 创建线程
 */
public class ThreadDemo1 {
    public static void main(String[] args) {
        //创建线程
        Thread thread = new MyThread();
        //启动线程
        thread.start();
    }
}

class MyThread extends Thread {
    @Override
    public void run() {
    //具体的业务代码
        Thread thread = Thread.currentThread();
        System.out.println("线程名称 " + thread.getName());
    }
}

在这里插入图片描述

继承Thread新建线程的缺点:因为java中有单继承特性,所以如果继承了Thread之后,就不能继承其他类。

  1. Thread的变种方式,使用匿名内部类
/**
 * 继承Thread 使用匿名内部类
 */
public class ThreadDemo3 {
    public static void main(String[] args) {
        Thread thread = new Thread() {
            @Override
            public void run() {
                //具体的业务代码
                Thread t = Thread.currentThread();
                System.out.println("线程名称 " + t.getName());
            }
        };
        //启动线程
        thread.start();
    }
}
  1. 实现Runnable接口
/**
 * 实现Runnable接口
 */
public class ThreadDemo2 {
    public static void main(String[] args) {
        //创建Runnable子对象
        MyThread2 myThread = new MyThread2();
        //创建线程
        Thread thread = new Thread(myThread);
        thread.start();
    }
}

class MyThread2 implements Runnable{
    @Override
    public void run() {
        Thread thread = Thread.currentThread();
        System.out.println("线程名称 " + thread.getName());
    }
}
  1. 实现Runnable接口,使用匿名内部类 (Runnable的变种1)(常用创建方式)
/**
 1. 实现Runnable接口,使用匿名内部类
 */
public class ThreadDemo4 {
    public static void main(String[] args) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                Thread t = Thread.currentThread();
                System.out.println("线程名称 " + t.getName());
            }
        });
        thread.start();
    }
}
  1. 使用Lambda匿名Runnable方式(jdk8之后的版本,不需要返回值时,建议使用这种创建方法)
/**
 * 使用 lambda 表达式
 */
public class ThreadDemo5 {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            Thread t = Thread.currentThread();
            System.out.println("线程名称 " + t.getName());
        });
        thread.start();
    }
}

以上五种创建线程的方法有一个共同点,都没有返回值,即当主线程运行完成后没有新线程的执行结果。

  1. 带返回值的Callable
/**
 * 带返回值的Callable
 */
public class ThreadDemo7 {
    //实现Callable接口
    public static class MyCallable implements Callable<Integer> {

        @Override
        public Integer call() throws Exception {
            //生成随机数0-19
            int randomNum = new Random().nextInt(20);
            System.out.println(Thread.currentThread().getName() + " 生成随机数:" + randomNum);
            return randomNum;
        }

        public static void main(String[] args) throws ExecutionException, InterruptedException {
            //创建Callable子对象
            MyCallable myCallable = new MyCallable();
            //使用FutureTask用于接收Callable结果的对象
            FutureTask<Integer> futureTask = new FutureTask<>(myCallable);
            //创建线程
            Thread thread = new Thread(futureTask);
            //启动线程
            thread.start();
            //得到线程执行的结果
            int result = futureTask.get();
            System.out.println(Thread.currentThread().getName() + " 中拿到新线程执行的结果为:" + result);
        }
    }
}

在这里插入图片描述

  1. 匿名Callable(常用创建方式)
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * 匿名Callable
 */
public class ThreadDemo8 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask<Integer> futureTask = new FutureTask<>(new Callable<Integer>() {
            @Override
            public Integer call() {
                int[] arr = new int[]{1, 2, 3};
                Integer result = arr[new Random().nextInt(2)];
                System.out.println(Thread.currentThread().getName() + " 随机数组元素:" + result);
                return result;
            }
        });
        //创建新线程
        Thread thread = new Thread(futureTask);
        thread.start();
        //FutureTask函数是用来接受返回值
        Integer result = futureTask.get();
        System.out.println(Thread.currentThread().getName() + " 中得到新线程的返回值:" + result);
    }

}

线程的常见构造方法

  1. Thread()
    创建线程对象
    在这里插入图片描述

  2. Thread(Runnable target)
    使用Runnable对象创建线程对象
    在这里插入图片描述

  3. Thread(Runnable target,String name)
    使用Runnable对象创建线程对象,并命名

在这里插入图片描述

  1. Thread(String name) 创建线程对象,并命名

在这里插入图片描述

可以使用jconsole观察该线程是否创建:
在这里插入图片描述

  1. Thread(ThreadGroup group,Runnable target)
    线程组,可以用来分组管理线程

package thread;

import java.util.Random;

/**
 * 线程组
 */
public class ThreadDemo11 {
    public static void main(String[] args) {
        //创建分组
        ThreadGroup group = new ThreadGroup("thread-group");
        //设置公共的任务(线程的任务)
        Runnable runTask = new Runnable() {
            @Override
            public void run() {
                //生成一个跑步能几秒到达终点的任务
                //随机生成数1-4
                int num = (1 + new Random().nextInt(5));
                try {
                    //sleep 的单位时毫秒
                    Thread.sleep(num * 1000);
                    System.out.println("选手到达终点:" + num + "s");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        //创建线程
        Thread t1 = new Thread(group, runTask);
        Thread t2 = new Thread(group, runTask);
        Thread t3 = new Thread(group, runTask);
        //启动线程
        t1.start();
        t2.start();
        t3.start();
        
        //等到所有人都到达终点,宣布成绩
        while (group.activeCount() != 0) {//activeCount 活跃线程数,所有人到达之后,才能宣布成绩
        }
        System.out.println("宣布成绩结果");

    }
}


在这里插入图片描述

线程中断

常见的两种方式:
1.通过自定义标记符来进行终端
2.调用interrupt()方法来中断

/**
 * 使用自定义标识符终止线程
 */
public class ThreadInterrupt1 {
    private volatile static boolean flag = false;

    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            while (!flag) {
                System.out.println("正在转帐...");
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("差点被发现了!");
        });
        thread.start();
        Thread.sleep(3000);
        //终止线程
        System.out.println("有内鬼终止交易");
        flag = true;
    }
}

在这里插入图片描述

/**
 * 使用interrupt终止线程
 */
public class ThreadInterrupt2 {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            //判断方法(两种方法)
//            while (!Thread.interrupted()) {
//                System.out.println("正在转账...");
//                try {
//                    Thread.sleep(500);
//                } catch (InterruptedException e) {
//                    break;
//                }
//            }
            while (!Thread.currentThread().isInterrupted()) {
                System.out.println("正在转账...");
//                try {
//                    Thread.sleep(500);
//                } catch (InterruptedException e) {
//                    break;
//                }
            }
            System.out.println("差点误了大事!");
            System.out.println("终止标志位2:" +Thread.currentThread().isInterrupted());
//            System.out.println("终止标志位4:" +Thread.interrupted());

        });
        thread.start();
        Thread.sleep(1000);

        //执行方法
        thread.interrupt();

    }
}

Thread.interrupted()和Thread.currentThread().isInterrupted()的区别
1.interrupted()属于静态方法,所有程序都可以直接调用的全局方法;而isInterrupted属于某个实例的方法
2.interrupted()在使用完后会重置终端标识符,而isInterrupted不会重置中断标识符

interrupted():
在这里插入图片描述
isInterrupted:
在这里插入图片描述

线程等待

import java.time.LocalDateTime;

/**
 * join示例
 * 第一种使用:直接使用线程.join()  意思是等待某种线程执行完成后再执行后续线程
 * 第二种使用: 使用线程.join(时间)  意思是等待上一种线程执行最多多长时间后就执行后续线程,不会等到上一种线程执行完
 * 等到某个线程执行完成后,在执行后续代码
 * join不设置等待参数的情况下,是无限等待
 * 优势(相比于isAlive):写法优雅,实行的是阻塞等待wait(),所运行的资源更少
 */
public class ThreadByJoin {
    //执行的顺寻应该为1.3.1.3
    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(() -> {
            //1.张三开始上班
            System.out.println("1.张三开始上班!" + LocalDateTime.now());
            //2.张三正在上班
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //3.张三下班
            System.out.println("3.张三下班!" + LocalDateTime.now());
        });
        thread1.start();
//        while (thread1.isAlive()) {
//        }
        thread1.join(500);
        Thread thread2 = new Thread(() -> {
            //1.李四开始上班!
            System.out.println("1.李四开始上班!" + LocalDateTime.now());
            //2.李四正在上班
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //3.李四下班!
            System.out.println("3.李四下班!" + LocalDateTime.now());
        });
        thread2.start();

    }
}

线程休眠

使用sleep休眠

Thread.sleep(3*1000);//单位是毫秒

使用TimeUnit休眠

        TimeUnit.DAYS.sleep(1);//天
        TimeUnit.HOURS.sleep(1);//小时
        TimeUnit.MINUTES.sleep(3);//分钟
        TimeUnit.SECONDS.sleep(3);//秒
        TimeUnit.MILLISECONDS.sleep(1);//毫秒
        TimeUnit.MICROSECONDS.sleep(1);//微秒
        TimeUnit.NANOSECONDS.sleep(1);//纳秒

获取线程实例

package thread;

import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * 实现多线程数组求和
 */
public class ThreadDemo6 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //记录开始执行的时间
        long stime = System.currentTimeMillis();
        int[] array = new int[10000000];
        //随机数初始化
        Random random = new Random();
        for (int i = 0; i < array.length; i++) {
            array[i] = (1 + random.nextInt(100));
        }

        // 创建两个线程相加
        // 计算偶数下标元素的和
        FutureTask<Integer> task1 = new FutureTask<>(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                int temp = 0;
                for (int i = 0; i < array.length; i = i + 2) {
                    temp += array[i];
                }
                System.out.println("线程1:" + temp);
                return temp;
            }
        });
        Thread t1 = new Thread(task1);
        t1.start();

        //计算奇数下标元素的和
        FutureTask<Integer> task2 = new FutureTask<Integer>(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                int temp = 0;
                for (int i = 1; i < array.length; i = i + 2) {
                    temp += array[i];
                }
                System.out.println("线程2:" + temp);
                return temp;
            }
        });
        Thread t2 = new Thread(task2);
        t2.start();
        
        int sum = task1.get() + task2.get();
        System.out.println("多线程数组总和:" + sum);
        //执行完成结束时间
        long etime = System.currentTimeMillis();
        //执行时间
        System.out.println("最终执行时间:" + (etime - stime));
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值