首页 > 编程语言 > 详细

java线程

时间:2019-03-11 22:24:38      阅读:153      评论:0      收藏:0      [点我收藏+]

进程:进行资源分配和调度的一个独立单位。

进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。

多线程应用场景

主要能体现到多线程提高程序效率。

举例: 迅雷多线程下载、分批发送短信等。

多线程创建方式

第一种继承Thread类 重写run方法

 1 /**
 2  * 
 3  * @classDesc: 功能描述:(创建多线程例子-Thread类 重写run方法)
 4  * @author: 余胜军
 5  * @version: v1.0
 6  * @copyright:上海每特教育科技有限公司
 7  */
 8 class CreateThread extends Thread {
 9     // run方法中编写 多线程需要执行的代码
10     publicvoid run() {
11         for (inti = 0; i< 10; i++) {
12             System.out.println("i:" + i);
13         }
14     }
15 }
16 publicclass ThreadDemo {
17 
18     publicstaticvoid main(String[] args) {
19         System.out.println("-----多线程创建开始-----");
20         // 1.创建一个线程
21         CreateThread createThread = new CreateThread();
22         // 2.开始执行线程 注意 开启线程不是调用run方法,而是start方法
23         System.out.println("-----多线程创建启动-----");
24         createThread.start();
25         System.out.println("-----多线程创建结束-----");
26     }
27 
28 }

技术分享图片

调用start方法后,代码并没有从上往下执行,而是有一条新的执行分之。注意:画图演示多线程不同执行路径。

 

第二种实现Runnable接口,重写run方法

 1 /**
 2  * 
 3  * @classDesc: 功能描述:(创建多线程例子-Thread类 重写run方法)
 4  * @author: 余胜军
 5  * @version: v1.0
 6  * @copyright:上海每特教育科技有限公司
 7  */
 8 class CreateRunnable implements Runnable {
 9 
10     @Override
11     publicvoid run() {
12         for (inti = 0; i< 10; i++) {
13             System.out.println("i:" + i);
14         }
15     }
16 
17 }
18 
19 /**
20  * 
21  * @classDesc: 功能描述:(实现Runnable接口,重写run方法)
22  * @author: 余胜军
23  * @version: v1.0
24  * @copyright:上海每特教育科技有限公司
25  */
26 publicclass ThreadDemo2 {
27     publicstaticvoid main(String[] args) {
28         System.out.println("-----多线程创建开始-----");
29         // 1.创建一个线程
30         CreateRunnable createThread = new CreateRunnable();
31         // 2.开始执行线程 注意 开启线程不是调用run方法,而是start方法
32         System.out.println("-----多线程创建启动-----");
33         Thread thread = new Thread(createThread);
34         thread.start();
35         System.out.println("-----多线程创建结束-----");
36     }
37 }

第三种使用匿名内部类方式

 1  System.out.println("-----多线程创建开始-----");
 2          Thread thread = new Thread(new Runnable() {
 3             public void run() {
 4                 for (int i = 0; i< 10; i++) {
 5                     System.out.println("i:" + i);
 6                 }
 7             }
 8         });
 9          thread.start();
10          System.out.println("-----多线程创建结束-----");

使用继承Thread类还是使用实现Runnable接口好?

 使用实现实现Runnable接口好,原因实现了接口还可以继续继承,继承了类不能再继承。

启动线程是使用调用start方法还是run方法?

开始执行线程 注意 开启线程不是调用run方法,而是start方法

调用run知识使用实例调用方法。

 守护线程

 Java中有两种线程,一种是用户线程,另一种是守护线程。

用户线程是指用户自定义创建的线程,主线程停止,用户线程不会停止

守护线程当进程不存在或主线程停止,守护线程也会被停止。

 使用setDaemon(true)方法设置为守护线程。

新建状态

   当用new操作符创建一个线程时, 例如new Thread(r),线程还没有开始运行,此时线程处在新建状态。 当一个线程处于新生状态时,程序还没有开始运行线程中的代码

就绪状态

一个新创建的线程并不自动开始运行,要执行线程,必须调用线程的start()方法。当线程对象调用start()方法即启动了线程,start()方法创建线程运行的系统资源,并调度线程运行run()方法。当start()方法返回后,线程就处于就绪状态。

     处于就绪状态的线程并不一定立即运行run()方法,线程还必须同其他线程竞争CPU时间,只有获得CPU时间才可以运行线程。因为在单CPU的计算机系统中,不可能同时运行多个线程,一个时刻仅有一个线程处于运行状态。因此此时可能有多个线程处于就绪状态。对多个处于就绪状态的线程是由Java运行时系统的线程调度程序(thread scheduler)来调度的。

运行状态

当线程获得CPU时间后,它才进入运行状态,真正开始执行run()方法.

阻塞状态

 线程运行过程中,可能由于各种原因进入阻塞状态:
    1>线程通过调用sleep方法进入睡眠状态;
    2>线程调用一个在I/O上被阻塞的操作,即该操作在输入输出操作完成之前不会返回到它的调用者;
    3>线程试图得到一个锁,而该锁正被其他线程持有;
    4>线程在等待某个触发条件;

死亡状态

有两个原因会导致线程死亡:
  1) run方法正常退出而自然死亡,
   2) 一个未捕获的异常终止了run方法而使线程猝死。
  为了确定线程在当前是否存活着(就是要么是可运行的,要么是被阻塞了),需要使用isAlive方法。如果是可运行或被阻塞,这个方法返回true; 如果线程仍旧是new状态且不是可运行的, 或者线程死亡了,则返回false.

join()方法作用

 1 class JoinThread implements Runnable {
 2 
 3     public void run() {
 4         for (int i = 0; i < 100; i++) {
 5             System.out.println(Thread.currentThread().getName() + "---i:" + i);
 6         }
 7     }
 8 }
 9 

18 public class JoinThreadDemo {
19 
20     public static void main(String[] args) {
21         JoinThread joinThread = new JoinThread();
22         Thread t1 = new Thread(joinThread);
23         Thread t2 = new Thread(joinThread);
24         t1.start();
25         t2.start();
26         try {
27        //其他线程变为等待状态,等t1线程执行完成之后才能执行join方法。
28             t1.join();
29         } catch (Exception e) {
30 
31         }
32         for (int i = 0; i < 100; i++) {
33             System.out.println("main ---i:" + i);
34         }
35     }
36 
37 }

Yield方法

 Thread.yield()方法的作用:暂停当前正在执行的线程,并执行其他线程。(可能没有效果)

yield()让当前正在运行的线程回到可运行状态,以允许具有相同优先级的其他线程获得运行的机会。因此,使用yield()的目的是让具有相同优先级的线程之间能够适当的轮换执行。但是,实际中无法保证yield()达到让步的目的,因为,让步的线程可能被线程调度程序再次选中。

结论:大多数情况下,yield()将导致线程从运行状态转到可运行状态,但有可能没有效果。

join作用是让其他线程变为等待,    t1.join();// 让其他线程变为等待,直到当前t1线程执行完毕,才释放。

thread.Join把指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行的线程。比如在线程B中调用了线程A的Join()方法,直到线程A执行完毕后,才会继续执行线程B。

多线程分批处理数据

需求:目前蚂蚁课堂有10万个用户,现在蚂蚁课堂需要做活动,给每一个用户发送一条祝福短信。

为了提高数程序的效率,请使用多线程技术分批发送据。

每开一个线程,都会占用CPU资源

服务器(电脑)配置 CPU 核数

新建用户实体类

 1 package com.itmayiedu.enity;
 2 /**
 3  * 
 4  */
 5 publicclass UserEntity {
 6 private String userId;
 7 private String userName;
 8 public String getUserId() {
 9 returnuserId;
10 }
11 publicvoid setUserId(String userId) {
12 this.userId = userId;
13 }
14 public String getUserName() {
15 return userName;
16 }
17 
18 publicvoid setUserName(String userName) {
19 this.userName = userName;
20 }
21 }

建立多线程UserThread 执行发送短信

 1 Class UserThreadextends Thread {
 2     private List<UserEntity>list;
 3 /**
 4      * 通过构造函数 传入每个线程需要执行的发送短信内容
 5      * 
 6      * @param list
 7      */
 8     public UserThread(List<UserEntity>list) {
 9         this.list = list;
10     }
11    /**
12      * 
13      */
14     publicvoid run() {
15         for (UserEntity userEntity : list) {
16             System.out.println("threadName:" + Thread.currentThread().getName() + "-学员编号:" + userEntity.getUserId()
17                     + "---学员名称:" + userEntity.getUserName());
18             // 调用发送短信具体代码
19         }
20     }
21 }

初始化数据

 1 publicstatic List<UserEntity> init() {
 2         List<UserEntity>list = new ArrayList<UserEntity>();
 3         for (inti = 1; i<= 140; i++) {
 4             UserEntity userEntity = new UserEntity();
 5             userEntity.setUserId("userId" + i);
 6             userEntity.setUserName("userName" + i);
 7             list.add(userEntity);
 8         }
 9         returnlist;
10 
11     }

计算分页工具类

public class ListUtils {
    /**
     * 
     */
    
    static public<T> List<List<T>> splitList(List<T> list, int pageSize) {
        int listSize = list.size();
        int page = (listSize + (pageSize - 1)) / pageSize;
        List<List<T>>listArray = new ArrayList<List<T>>();
        for (int i = 0; i<page; i++) {
            List<T>subList = new ArrayList<T>();
            for (int j = 0; j<listSize; j++) {
                int pageIndex = ((j + 1) + (pageSize - 1)) / pageSize;
                if (pageIndex == (i + 1)) {
                    subList.add(list.get(j));
                }
                if ((j + 1) == ((j + 1) * pageSize)) {
                    break;
                }
            }
            listArray.add(subList);
        }
        return listArray;
    }
}

实现发送短信

 1 Public staticvoid main(String[] args) {
 2         // 1.初始化用户数据
 3         List<UserEntity>listUserEntity = init();
 4         // 2.计算创建创建多少个线程并且每一个线程需要执行“分批发送短信用户”
 5         // 每一个线程分批跑多少
 6         intuserThreadPage = 50;
 7         // 计算所有线程数
 8         List<List<UserEntity>>splitUserList = ListUtils.splitList(listUserEntity, userThreadPage);
 9         intthreadSaze = splitUserList.size();
10         for (inti = 0; i<threadSaze; i++) {
11             List<UserEntity>list = splitUserList.get(i);
12             UserThread userThread = new UserThread(list);
13             // 3.执行任务发送短信
14             userThread.start();
15         }
16 
17     }

 

----总结来自蚂蚁课堂&每特学院材料

java线程

原文:https://www.cnblogs.com/dingpeng9055/p/10513577.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!