通过上一篇 多线程并发 (一) 了解 Java 虚拟机 - JVM 了解了java 虚拟机的构成以及对象的创建等。从Java虚拟机栈我们知道每当我们创建一个线程JVM就会给我们的线程分配一个私有的内存空间和程序计数器记录当前线程运行的次行代码的地址。了解了Thread之后,通过多线程编程进而引入锁(下篇)的概念。
1. 线程简介

线程是进程中可独立执行的最小单位,也是 CPU 资源分配的基本单位。

2. 线程的四个属性(1)编号Id
              线程的编号(id)用于标识不同的线程,每条线程拥有不同的编号。
    (2) 名字
             每个线程都有自己的名字(name),名字的默认值是 Thread-线程编号,比如 Thread-0 。除了默认值,我们也可以给线程设置名字,以我们自己的方式去区分每一条线程。
    (3)类别
            分为守护线程和用户线程,我们可以通过 setDaemon(true) 把线程设置为守护线程。GC线程是守护线程,对于守护线程JVM退出时不会考虑次线程是否持行完毕。
    (4)优先级
            线程的优先级(Priority)用于表示应用希望优先运行哪个线程,线程调度器会根据这个值来决定优先运行哪个线程。
            Java 中线程优先级的取值范围为 1~10,默认值是 5,Thread 中定义了下面三个优先级常量。
            最低优先级:MIN_PRIORITY = 1
            默认优先级:NORM_PRIORITY = 5
            最高优先级:MAX_PRIORITY = 10
3. 线程的六个方法

线程的常用方法有六个,它们分别是三个非静态方法 start()、run()、join() 和三个静态方法 currentThread()、yield()、sleep() 。我们只关注start()、join()、yield()、sleep(),另外run()、currentThread()容易理解。
(1)yield() 
      顾名思义yield英文 让 的意思。当t.yield() 持行之后 t 回到就绪状态,所有线程重新抢用cpu。
(2)join() 
      t2正在运行,这时在t2线程中调用 t1.join() ,这是让t2 等待线程t1 结束了,再运行。次方法可以让线程按顺序持行。自己线程中调用自己的join方法是无意义的。
(3)sleep()
      暂停阻塞等待一段时间,时间过了就继续。这个方法是不释放锁的。
(4)start()
     启动线程,让cpu调度器调度开启线程持行run()方法。而直接调用run()方法只是运行当前run方法,不会开启线程。

4.线程运行状态

线程调用状态图

分析:1. new 的状态(NEW)
           2. start() 之后线程到达就绪状态等待cpu调度,cpu调度了 就是运行状态。(RUNNABLE)
           3. 调用了 TImedWaiting 就回到就绪状态,结束之后自动到运行状态(TIMED_WAITING)
           4. 调用 Waiting 就绪然后持行相应的方法到运行(WAITING)
           5. 调用 Blocked 等待进入同步代码快的锁。(BLOCKED)
           6. 结束状态Teminated(TERMINATED)
线程被挂起:正在cpu中调度的线程,cpu把该线程丢出去,持行其他线程,这就是线程被挂起。之后又回来持续该线程。(cpu每次只能持行一个线程)
5.Java 线程调度原理

在任意时刻,CPU 只能执行一条机器指令,每个线程只有获取到 CPU 的使用权后,才可以执行指令。
也就是在任意时刻,只有一个线程占用 CPU,处于运行的状态。
多线程并发运行实际上是指多个线程轮流获取 CPU 使用权,分别执行各自的任务。
线程的调度由 JVM 负责,线程的调度是按照特定的机制为多个线程分配 CPU 的使用权。
线程调度模型分为两类:分时调度模型和抢占式调度模型。

1.分时调度模型
分时调度模型是让所有线程轮流获取 CPU 使用权,并且平均分配每个线程占用 CPU 的时间片。
2.抢占式调度模型
JVM 采用的是抢占式调度模型,也就是先让优先级高的线程占用 CPU,如果线程的优先级都一样,那就随机选择一个线程,并让该线程占用 CPU。
也就是如果我们同时启动多个线程,并不能保证它们能轮流获取到均等的时间片。
如果我们的程序想干预线程的调度过程,最简单的办法就是给每个线程设定一个优先级。
6.线程创建的四种方式
    1)继承Thread类创建线程
    2)实现Runnable接口创建线程
    3)使用Callable和Future创建线程
    4)使用线程池例如用Executor框架
具体代码也是非常简单,仅仅贴出Future的代码:

[AppleScript] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
public class MyTask  implements Callable<Object>{   
    private String args1;
    private String args2;
    //构造函数,用来向task中传递任务的参数
    public  MyTask(String args1,String args2) {
        this.args1=args1;
        this.args2=args2;
    }
    //任务执行的动作
    @Override
    public Object call() throws Exception {
         
        for(int i=0;i<100;i++){
            System.out.println(args1+args2+i);
        }
        return true;
}
[AppleScript] 纯文本查看 复制代码
1
2
3
4
5
6
MyTask myTask = new MyTask("www", "www");
FutureTask<Object> futureTask = new FutureTask<>(myTask);
Thread thread = new Thread(futureTask);
thread.start();
//get()阻塞等待直到任务执行完成。
boolean result = (boolean) futureTask.get();

7.LockSupport
我们可以使用它来阻塞和唤醒线程,功能和wait,notify有些相似,但是LockSupport比起wait,notify功能更强大,也好用的多。
1)对比wait,notify
wait和notify都是Object中的方法,在调用这两个方法前必须先获得锁对象。
当对象的等待队列中有多个线程时,notify只能随机选择一个线程唤醒,无法唤醒指定的线程。
LockSupport的话,我们可以在任何场合使线程阻塞,同时也可以指定要唤醒的线程。

[AppleScript] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
public class LockSupportTest {
  
    public static void main(String[] args) {
        Thread parkThread = new Thread(new ParkThread());
        parkThread.start();
        System.out.println("开始线程唤醒");
        LockSupport.unpark(parkThread);
        System.out.println("结束线程唤醒");
  
    }
  
    static class ParkThread implements Runnable{
  
        @Override
        public void run() {
            System.out.println("开始线程阻塞");
            LockSupport.park();
            System.out.println("结束线程阻塞");
        }
    }
}

可指定线程阻塞和唤醒。摘学于:https://www.cnblogs.com/takumicx/p/9328459.html
8.CountDownLatch
CountDownLatch开启一组线程,让每个线程去持行自己的任务,等所有线程都持行完毕后,再向下持行代码。比如我们开启一组线程去同步服务器的数据有 播放记录,下载记录,收藏记录等等用户信息。

[AppleScript] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
CountDownLatch latch = new CountDownLatch(5);
        for (int i =0;i<5;i++){
            new Thread(new MyTask(latch,i*1000,i)).start();
        }
        try {
            latch.await();
            Log.e("WXY--","All the tasks are over.");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
[AppleScript] 纯文本查看 复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
public class MyTask implements Runnable {
    CountDownLatch latch;
    int delayTime; // Test
    int curThread;
    public MyTask(CountDownLatch latch,int delayTime,int curThread) {
        this.latch = latch;
        this.delayTime = delayTime;
        this.curThread = curThread;
    }
    @Override
    public void run() {
        try {
            Thread.sleep(delayTime);
            Log.e("WXY--","current task = " + curThread);
            latch.countDown();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

这篇相对简单主要是认识线程,了解线程的方法。介绍了两个线程同步的类。

更多技术资讯可关注:itheimaGZ获取

多线程并发 了解 Thread的更多相关文章

  1. Java面试题整理一(侧重多线程并发)

    1..是否可以在static环境中访问非static变量? 答:static变量在Java中是属于类的,它在所有的实例中的值是一样的.当类被Java虚拟机载入的时候,会对static变量进行初始化.如 ...

  2. HashMap多线程并发问题分析

    转载: HashMap多线程并发问题分析 并发问题的症状 多线程put后可能导致get死循环 从前我们的Java代码因为一些原因使用了HashMap这个东西,但是当时的程序是单线程的,一切都没有问题. ...

  3. 用读写锁三句代码解决多线程并发写入文件 z

    C#使用读写锁三句代码简单解决多线程并发写入文件时提示“文件正在由另一进程使用,因此该进程无法访问此文件”的问题 在开发程序的过程中,难免少不了写入错误日志这个关键功能.实现这个功能,可以选择使用第三 ...

  4. 由获取微信access_token引出的Java多线程并发问题

    背景: access_token是公众号的全局唯一票据,公众号调用各接口时都需使用access_token.开发者需要进行妥善保存.access_token的存储至少要保留512个字符空间.acces ...

  5. ThreadLocal 多线程并发,数据隔离

    ThreadLocal:  创建一个线程本地变量. 本质:在ThreadLocal类中有一个Map,用于存储每一个线程的变量的副本. 优点:既实现多线程并发,游兼顾数据的安全性. 区别:Synchro ...

  6. Cocos2d-x优化中多线程并发访问

    多线程并发访问在Cocos2d-x引擎中用的不是很多,这主要是因为中整个结构设计没有采用多线程.源自于Objective-C的Ref对象,需要使用AutoreleasePool进行内存管理,Autor ...

  7. 多线程并发 synchronized对象锁的控制与优化

    本文针对用户取款时多线程并发情境,进行相关多线程控制与优化的描述. 首先建立用户类UserTest.业务操作类SynchronizedTest.数据存取类DataStore,多线程测试类MultiTh ...

  8. Cocos2d-x优化中多线程并发訪问

    多线程并发訪问在Cocos2d-x引擎中用的不是非常多,这主要是由于中整个结构设计没有採用多线程. 源自于Objective-C的Ref对象,须要使用AutoreleasePool进行内存管理,Aut ...

  9. 多线程并发执行任务,取结果归集。终极总结:Future、FutureTask、CompletionService、CompletableFuture

    目录 1.Futrue 2.FutureTask 3.CompletionService 4.CompletableFuture 5.总结 ================正文分割线========= ...

随机推荐

  1. Eclipse Springboot项目Dokcer

    配置好Dockerfile FROM openjdk:8-jdk-alpine ARG JAR_FILE=target/*.jar COPY ${JAR_FILE} app.jar ENTRYPOIN ...

  2. str_replace用法

    语法 str_replace(find,replace,string,count) 参数 描述 find 必需.规定要查找的值. replace 必需.规定替换 find 中的值的值. string ...

  3. 17.3.12---xmlrpclib模块

    1----XML-RPC是一种使用xml文本的方式利用http协议传输命令和数据的rpc基址,我们用pythom的想mlrpclib模块可以让程序与其他任何语言编写的XML-RPC服务器进行数据传输 ...

  4. Innodb-内存架构与特性

    参考文档 Innodb特性buffer_pool http://mysql.taobao.org/monthly/2017/05/01/?spm=a2c4e.11153940.blogcont2812 ...

  5. PAT Basic 反转链表 (25) [链表]

    题目 给定⼀个常数K以及⼀个单链表L,请编写程序将L中每K个结点反转.例如:给定L为1→2→3→4→5→6,K为3,则输出应该为3→2→1→6→5→4:如果K为4,则输出应该为4→3→2→1→5→6, ...

  6. 注册登录页面修订-Python使用redis-手机验证接口-发送短信验证

    登录页面修订 views.Login.vue <template> <div class="login box"> <img src="@/ ...

  7. 第五章——Pytorch中常用的工具

    2018年07月07日 17:30:40 __矮油不错哟 阅读数:221   1. 数据处理 数据加载 ImageFolder DataLoader加载数据 sampler:采样模块 1. 数据处理 ...

  8. Comet OJ - Contest #3 D可爱的菜菜子(线段树+线性基的合并)

    这题其实挺经典的,看到求异或最大,显然想到的是线性基,不过这怎么维护?当然区间有关的东西都可以上线段树,区间修改时记录每个点的修改量k,然后合并线性基时再加入线性基.因为线性基是求一组极大线性无关组, ...

  9. 将List 分成n个长度由调用者指定的子List

    public static void main(String[] args) { List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8); ...

  10. 深度学习数据集MNIST ImageNet COCO PASCAL VOC介绍

    参考文档 深度学习数据集汇总介绍 1.  MNIST 深度学习领域的“Hello World!”,入门必备!MNIST是一个手写数字数据库,它有60000个训练样本集和10000个测试样本集,每个样本 ...