【Java多线程】总结(一)线程的创建 线程方法 附详细()代码(更新

  1. 进程:是指一个内存中正在运行的应用程序。每个进程都有自己的内存空间和系统资源。进程是系统资源分派和调度的基本单位。
  2. 线程:线程是进程的一个实体,是操作系统中独立运行的基本单位,只在运行时拥有少量资源,线程是CPU调度和分派的基本单位;
    1. 单线程:一个进程如果只有一条执行路径,则称为单线程程序;
    2. 多线程:一个进程有多个执行路径,则称为多线程程序;
    3. 进程和线程的区别总结:
      1. 进程是系统资源分派和调度的基本单位,而线
        程是CPU调度和分派的基本单位;
      2. 进程拥有独立资源而线程几乎不拥有独立资源。
  3. 多线程的实现方式:
    1. 继承Thread类:
public class ThreadDemo_inherit {
    public static void main(String[] args) {
        //获得当前线程
        Thread mainThread=Thread.currentThread();
        System.out.println("线程名称:"+mainThread.getName());
        //3.启动线程(start())
        Thread thread=new MyThread();
        thread.start();

    }
}
//1.定义一个myThread类继承Thread类
class MyThread extends Thread{
    //2.在myThread类中重写run方法创建myThread类的对象
    @Override
    public void run() {
        //具体业务代码
        System.out.println("你好线程");
        Thread thread=Thread.currentThread();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("线程名称:"+thread.getName());
    }
}
/*
线程名称:main
你好线程
线程名称:Thread-0
 */

    1. 实现runnable接口:
public class ThreadDemo_runn {
    public static void main(String[] args) {
        //3.创建实现Runnable接口的类的对象
        MyThread2 myThread2=new MyThread2();
        //4.创建线程,把myrunnable对象作为构造方法的参数
        Thread thread=new Thread(myThread2);
        thread.start();


    }
}
//1.定义类实现Runnable接口
class MyThread2 implements Runnable{
    //2.重写方法
    @Override
    public void run() {
        //具体业务代码
        Thread thread=Thread.currentThread();
        System.out.println("线程执行"+thread.getName());

    }
}
//线程执行Thread-0
    1. 2的另一种写法:匿名内部类
public class ThreadDemo_runn2 {
    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. 2的另一种写法:lambda表达式
public class ThreadDemo_runn3 {
    public static void main(String[] args) {
        // lambda表达式
        Thread thread=new Thread(()->{
            //具体业务代码
            Thread t=Thread.currentThread();
            System.out.println("线程执行:"+t.getName());

        });
        thread.start();
    }
}
    1. 创建线程并初始化
public class ThreadDemo_5 {
    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. callable+Future:
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * 实现callable新建线程
 */
public class ThreadDemo_6 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //创建Callable实例
        MyCallable myCallable = new MyCallable();
        //用于接收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);
    }
}
/**
 * Callable<T>泛型可以是任意类型
 */
class MyCallable implements Callable<Integer>{
    @Override
    public Integer call() throws Exception {
        //生成随机数0—9
        int randomNum=new Random().nextInt(10);
        System.out.println(Thread.currentThread().getName()+"---随机数:"+randomNum);
        return randomNum;
    }
}
/**
 * Thread-0---随机数:4
 * main---新线程的返回结果为:4
 */
    1. 6+lambda:
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class ThreadDemo_7 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask<String> futureTask = new FutureTask<>(new Callable<String>() {
            @Override
            public String call() throws Exception {
                //新线程执行的业务代码
                String[] arr=new String[]{"java","woaijava","Thread"};
                String result=arr[new Random().nextInt(3)];
                System.out.println(Thread.currentThread().getName()+"---字符串:"+result);
                return result;
            }
        });
        //创建新线程
        Thread thread=new Thread(futureTask);
        //启动线程
        thread.start();
        //接收新线程的结果
        String  result = futureTask.get();
        System.out.println(Thread.currentThread().getName()+"---新线程的返回结果为:"+result);
    }
}
/**
 * Thread-0---字符串:woaijava
 * main---新线程的返回结果为:woaijava
 */
  1. 线程常用构造方法
方法说明
Thread()创建线程对象
Thread(Runnable target)使用Runnable对象创建对象
Thread(String name)创建线程对象并命名
Thread(Runnable target, String name)使⽤ Runnable 对象创建线程对象,并命名
Thread(ThreadGroup group, Runnable target)线程可以被⽤来分组管理,分好的组即为线程 组
Thread t1 = new Thread();
Thread t2 = new Thread(new MyRunnable());
Thread t3 = new Thread("这是我的名字");
Thread t4 = new Thread(new MyRunnable(), "这是我的名字");

  1. 线程分组使用:
import java.util.Random;

public class ThreadDemo_10 {
    public static void main(String[] args) {
        // 1.创建一个线程分组
        ThreadGroup group=new ThreadGroup("thread-group");
        // 2.定义一个公共的任务
        Runnable runTask=new Runnable(){
            @Override
            public void run() {//业务
                int num=new Random().nextInt(3);
                //n秒后到达终点
                try {
                    Thread.sleep(num*1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //得到执行此方法的线程
                Thread t=Thread.currentThread();
                System.out.println(t.getName()+"--选手到达终点"+num+"s");
            }
        };
        // 3.线程(运动员)
        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){
        }
        System.out.println("宣布成绩");
    }
}

** 如果在主线程启动新的线程 那么新线程和主线程各自独立运行 即要等所有人到达终点后宣布成绩

  1. 线程常用属性:
属性获取⽅法
1IDgetId()
2名称getName()
3状态getState()
4优先级getPriority()
5是否守护(后台)线程isDaemon()
6是否存活isAlive()
7是否被中断isInterrupted()
8让出执⾏权yield()
    1. ID 是线程的唯⼀标识,不同线程不会重复,是动态分配名称是各种调试⼯具⽤到,可能重复
    2. 名称可能会重复,是各种调试⼯具⽤到
    3. 状态表示线程当前所处的⼀个情况,优先级⾼的线程理论上来说更容易被调度到
public class ThreadDemo_11 {
    public static void main(String[] args) throws InterruptedException {
        Thread t=new Thread(new Runnable() {
            @Override
            public void run() {
                Thread tt=Thread.currentThread();
                System.out.println("线程状态2:"+tt.getState());
            }
        });
        //打印线程的状态
        System.out.println("线程状态:"+t.getState());
        t.start();
        //再次打印线程状态
        Thread.sleep(1000);
        System.out.println("线程状态3:"+t.getState());
    }
}
/**
 * 线程状态:NEW
 * 线程状态2:RUNNABLE
 * 线程状态3:TERMINATED
 */
    1. 多个线程的执行是随机的,优先级高的理论上说更容易被调度到(高优先级获取cpu时间片的概率高)
public class ThreadDemo_priority {
    private final static int MAXCOUNT=1000;
    public static void main(String[] args) {
        Thread t1=new Thread(new Runnable() {
            @Override
            public void run() {
                Thread t=Thread.currentThread();
                int priority=t.getPriority();
                for (int i = 0; i < MAXCOUNT; i++) {
                    System.out.println(t.getName()+"--优先级:"+priority);
                }
            }
        },"线程1");
        t1.setPriority(10);
        Thread t2=new Thread(new Runnable() {
            @Override
            public void run() {
                Thread t=Thread.currentThread();
                int priority=t.getPriority();
                for (int i = 0; i < MAXCOUNT; i++) {
                    System.out.println(t.getName()+"--优先级:"+priority);
                }
            }
        },"线程2");
        t2.setPriority(Thread.NORM_PRIORITY);
        Thread t3=new Thread(new Runnable() {
            @Override
            public void run() {
                Thread t=Thread.currentThread();
                int priority=t.getPriority();
                for (int i = 0; i < MAXCOUNT; i++) {
                    System.out.println(t.getName()+"--优先级:"+priority);
                }
            }
        },"线程3");
        t3.setPriority(Thread.MIN_PRIORITY);
        t1.start();
        t2.start();
        t3.start();
    }
}

    1. 关于守护线程(后台线程),需要记住⼀点:JVM会在⼀个进程的所有⾮后台(守护)线程结束后,才会结束运⾏。
守护线程示例
public class ThreadDemo_Daemon {
   public static void main(String[] args) throws InterruptedException {
       Thread t=Thread.currentThread();
       System.out.println(t.getName()+"---是否是守护线程:"+t.isDaemon());
       Thread t1=new Thread(()->{
           Thread tt1=Thread.currentThread();
           System.out.println(tt1.getName()+"---是否是守护线程:"+tt1.isDaemon());
           Thread t2=new Thread(()->{
               Thread tt2=Thread.currentThread();
               System.out.println(tt2.getName()+"---是否是守护线程:"+tt2.isDaemon());
           },"子线程的子线程");
           t2.start();
       },"子线程");
       t1.setDaemon(true);
       t1.start();
       //将主线程休眠
       Thread.sleep(1000);
   }
}
/**
* main---是否是守护线程:false
* 子线程---是否是守护线程:true
* 子线程的子线程---是否是守护线程:true
*/
      1. 对比用户线程和守护线程
 public class ThreadDemo_Daemon2 {
    public static void main(String[] args) throws InterruptedException {
//        userThread();
        daemonThread();
        Thread.sleep(500);
    }

    private static void daemonThread() {
        Thread t=new Thread(()->{
            for (int i = 0; i < 10; i++) {
                System.out.println("执行:"+i);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t.setDaemon(true);
        t.start();
    }

    /**
     * 用户线程
     */
    private static void userThread() {
        Thread t=new Thread(()->{
            for (int i = 0; i < 10; i++) {
                System.out.println("执行:"+i);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t.start();
    }
}
/**
 * 执行:0
 * 执行:1
 * jvm不会等待守护线程执行完再退出,只会等待用户线程执行完才会退出
 */
      1. 线程的分类:
        1. 用户线程( main 默认用户线程):默认情况下在用户线程下创建也是用户线程

          1. 守护线程(后台线程):守护线程是为⽤户线程服务的,⽤户线程全部结束之后,守护线程会跟随结束 ,默认情况下在守护线程下创建的子线程也是守护线程。

          2. start方法的调用在设置类型之后

    1. 是否存活,即简单的理解,为 run ⽅法是否运⾏结束了
      1.

public class ThreadDemo_isAlive {
    public static void main(String[] args) throws InterruptedException {
        Thread t=new Thread(()->{
            //得到当前线程
            Thread tt=Thread.currentThread();
            System.out.println("线程是否存活2:"+tt.isAlive());
        });
        System.out.println("线程是否存活:"+t.isAlive());
        t.start();
        System.out.println("线程是否存活3:"+t.isAlive());
        Thread.sleep(1000);
        System.out.println("线程是否存活4:"+t.isAlive());
    }
}
/**
 * 线程是否存活:false
 * 线程是否存活3:true
 * 线程是否存活2:true
 * 线程是否存活4:false
 */
      1. 利用isAlive()方法确认线程是否执行完毕:
public class ThreadDemo_isAlive2 {
    public static void main(String[] args) {
        Thread t=new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("线程执行完了");
        });
        t.start();
        while(t.isAlive()){

        }
        System.out.println("确认线程执行完了");
    }
}
/**
 * 线程执行完了
 * 确认线程执行完了
 */
      1. .isAlive() 类似于 join()
        join() 线程等待:等待某个线程执行完之后,再执行后续的代码 优点:写法优雅 阻塞等待 消耗系统资源少
        join() :等待线程结束
        join(long millis):最多等待多少毫秒
/**
 * join示例
 */
public class ThreadDemo_join {
    public static void main(String[] args) throws InterruptedException {
        Thread t1=new Thread(()->{
            //t1开始上班
            System.out.println("t1开始上班");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //
            System.out.println("t1下班");
        });
        t1.start();
        //等待t1执行完,再执行后面的代码
        t1.join();

        Thread t2=new Thread(()->{
            //t开始上班
            System.out.println("t2开始上班");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //
            System.out.println("t2下班");
        });
        t2.start();
    }
}
    1. 线程终止的方法
      1. 自定义标识符终止线程
package ThreadFun;
public class ThreadInterrupt {
    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(1000);
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           }
            System.out.println("a 差点误了大事");
        });
        thread.start();
        Thread.sleep(2000);
        //终止线程
        System.out.println("有内鬼终止交易~");
        flag=true;
    }
}
      1. 调用isInterrupted()来终止线程
package ThreadFun;
public class ThreadInterrupt2 {
    public static void main(String[] args) throws InterruptedException {
        Thread thread=new Thread(()->{
//            while(!Thread.interrupted()){
            while(!Thread.currentThread().isInterrupted()){
                System.out.println("正在转帐。。");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
//                    e.printStackTrace();
                    break;
                }
            }
            System.out.println("啊啊差点误了大事");
        });
        thread.start();
        Thread.sleep(3000);
        thread.interrupt();
        System.out.println("有内鬼。。");
    }
}
/**
 * 正在转帐。。
 * 正在转帐。。
 * 有内鬼。。
 * 啊啊差点误了大事
 */
      1. interrupt() 需要配合Thread.interrupted/Thread.currentThread().isInterrupted()使用
        1. isInterrupted()和interrupted的区别:
          1. interruped()属于静态方法,所有程序都可以直接调用的方法,而isInterrupted()属于某个实例的方法
          2. interrupted()在使用完会重置,而另外一个不会
    1. yield():出让cpu执行权,让线程调度器重新调度线程,但还是有一定的几率再依次调用到出让cpu的线程上,这一次就会执行线程的方法了,因为yield()已经执行
public class ThreadDemoYield {
    public static void main(String[] args) {
        Thread t1=new Thread(()->{
            Thread cThread=Thread.currentThread();
            for (int i = 0; i < 100; i++) {
                //让出cpu执行权
                Thread.yield();
                System.out.println("执行了线程:"+cThread.getName());
            }
        },"张三");
        t1.start();
        new Thread(()->{
            Thread cThread=Thread.currentThread();
            for (int i = 0; i < 100; i++) {
                System.out.println("执行了线程:"+cThread.getName());

            }
        },"李四").start();
    }
}
  1. 休眠当前线程:
    1. 使⽤ sleep 休眠
public class ThreadDemoSleep {
    public static void main(String[] args) throws InterruptedException {
        Thread thread=new Thread(()->{
            try {
                Thread.sleep(1000*60*60);
            } catch (InterruptedException e) {
                System.out.println("我接收到了终止指令");
//                e.printStackTrace();
            }
        });
        thread.start();

        Thread.sleep(1000);
        System.out.println("子线程终止 thread");
        thread.interrupt();
    }
}
/**
 * 子线程终止 thread
 * 我接收到了终止指令
 */

    1. 使⽤ TimeUnit 休眠
//使用TimeUtil休眠
public class ThreadTimeUtil {
    public static void main(String[] args) throws InterruptedException {
        System.out.println("主线程开始了"+ LocalDateTime.now());
        TimeUnit.SECONDS.sleep(1);
       // Thread.sleep(1000*60*60*24);
        System.out.println("主线程又开始执行了"+LocalDateTime.now());
    }
}
//主线程开始了2022-04-01T18:17:44.074
//主线程又开始执行了2022-04-01T18:17:45.086

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值