java线程(1)-线程初步

1.并行和并发

并行和并发是即相似又有区别:

并行:指两个或者多个事件在同一时刻点发生。

并发:指两个或多个事件在同一时间段内发生

在操作系统中,并发性是指在一段事件内宏观上有多个程序在同时运行,但是单CPU系统中,每一时刻仅能有一道程序执行。故微观上这些程序只能是分时交替执行

单核处理器的计算机肯定是不能并行的处理多个任务的,只能是多个任务在单个CPU上并发运行,同理,线程也是一样的,从宏观角度上理解是并行运行的,但是从微观角度上分析却是串行运行的,即一个线程一个线程的去运行,当系统只有一个CPU时,线程会以某种顺序执行多个线程,我们把这种情况称之为线程调度

2.理解进程和线程

进程和线程:

进程是指一个内存中运行中的应用程序,每一个进程都有自己独立的一块内存空间,一个应用程序可以同启动多个进程。

大多数的时候,操作系统都不需要一个进程方法其他进程的空间,也就是说进程之间的通信是很不方便的。此时我们引入“线程”这门技术,来解决这个问题

线程是指进程中一个执行任务,一个进程可以同时并发运行多个线程,如:多线程下载软件。

多任务系统:该系统可以运行多个进程,一个进程可以执行多个任务,一个进程可以包含多个线程

一个进程至少有一个线程,为了提高效率,可以在一个进程中开启多个执行任务,即多线程

多进程:操作系统中同时运行的多个程序

多线程:在同一个进程中同时运行的多个任务

在操作系统中允许多个任务,每一个任务就是一个进程,每一个进程也可以同时执行多个任务,每一个任务就是线程

进程和线程的区别:

进程:有独立的内存空间,进程中的数据存放空间(堆空间和栈空间)是独立的,至少有一个线程

线程:堆空间是共享的,栈空间是独立的,线程消耗的资源也比进程小,相互之间可以影响的,又称为轻型进程或进程元

因为一个进程中的多个线程是并发的,那么从微观角度来考虑也是有先后顺序的,那么哪一个线程执行完全取决于CPU调度器(JVM来调度),程序员是控制不了的

我们可以把线程并发性看做是多个线程在瞬间抢CPU资源,谁抢到了资源谁就运行,这也就造成了多线程的随机性

java程序的进程里至少包含主线程和垃圾回收线程(后台线程)

线程调度:

计算机通常只有一个CPU时,在任意时刻只能执行一条计算机指令,每一个进程只有获取CPU的使用权才能执行指令。所谓多进程并发性,从宏观上来看,其实就是各个进程轮流获得CPU的使用权,分别执行各自的任务

那么,在可运行池中,会有多个线程处理就绪状态等到CPU,JVM就负责了线程的调度

JVM采用的是抢占式调度,没有采用分时调度,因此可能造成多线程执行结果的随机性。

3.多线程的优势

多线程作为一种多任务,并发的工作方法,当然有其存在的优势:

1.进程之前不能共享内存,而线程之间共享内存(堆内存)则很简单

2.系统创建进程时需要为该进程重新分配系统资源,创建线程则代价小的多,因此实现多任务并发时,多线程效率更高

3.java语言本身内置多线程功能的支持,而不是单纯作为底层系统的调度方式,从而简化了多线程编程

4.创建一个简单的多线程

在java代码中如何去运行一个进程:

方式1:Runtime类的exec方法

方式2:ProcessBuilder的start方法

//在java中如何开启一个进程:运行记事本程序
public class ProcessDemo{
public static voild main(String[] args) throws Exception{
//方式1:使用Runtime类的exec方法
Runtime runtime = Runtime.getRuntime();
runtime.exce("notepad");
//方式2:使用ProcessBuilder的start方法
ProcessBuilder pb = new ProcessBuilder("notepad");
pb.start();
}
}

5.使用继承方式和实现方式创建并启动线程

创建和启动线程,传统有两种方法:

方式1:继承Thread类

方式2:实现Runnable接口

线程类:Thread类(java.lang.Thread)和Thread的子类才能称之为线程类(API有详细例子)

方式1:继承Thread类

步骤:

1.定义一个类A继承于java.lang.Thread类

2.在A类中覆盖Thread类中的run方法

3.我们在run方法中编写需要执行的操作->run方法里的线程执行体

4.在main方法(线程)中,创建线程对象,并启动线程

创建线程类: A类 a = new A类();

调用线程对象的start方法,a.start();//启动一个线程

注意:千万不要调用run方法,如果调用run方法,好比是对象调用方法,依然还是只有一个线程,并没有开启新的线程.

方式1:继承Thread类

//计算大于某一规定值的质数的线程可以写成:
//1.定义Thread的集成类
class PrimeThread extends Thread{
long mainPrime;
public PrimeThread(long mainPrime){
this.mainPrime = mainPrime;
} public void run(){
//TODO
}
} //2.调用线程类.创建并启动一个线程
PrimeThread p = new PrimeThread(143);
p.start();//注意是调用start方法

方式2:实现Runnable接口

步骤:

1.定义一个类A继承于java.lang.Thread类

2.在A类中覆盖Thread类中的run方法

3.我们在run方法中编写需要执行的操作->run方法里的线程执行体

4.在main方法(线程)中,创建线程对象,并启动线程

创建线程类: Thread(Runnable target);//分配新的Thread对象

调用线程对象的start方法,a.start();//启动一个线程

//方式2,是声明实现 Runnable 接口的类
class PrimeRun implements Runable{
long mainPrime;
public PrimeRun(long mainPrime){
this.mainPrime = mainPrime;
} public void run(){
//TODO
}
} //创建并启动一个线程:
PrimeRun p = new PrimeRun(143);
Thread t = new Thread(p);
t.start();
//每个线程都有一个标识名,多个线程可以同名。如果线程创建时没有指定标识名,就会为其生成一个新名称。

6.使用匿名内部类来创建线程

只适用于某一个类只适用一次的情况。

匿名内部类其实就是把5中步骤1,2,3放在4中写,例如创建一个Runnable接口的匿名内部类,上面的改成:

new Thread(new Runnable(){
public void run(){
//TODO
}
}).start();

通过继承方式的内部类也是可以这样写的,写的时候就不用声明继承了,直接在{}里面写run()方法就可以了。

new Thread(){
public void run(){
//TODO
}
}.start();

这种方式用的比较少

7.案例

我们写一个案例来具体说明:

需求:有50个苹果,请三个小朋友来吃,A,B,C三个人可以同时吃苹果,用多线程来实现

分析:

可以先定义线程对象,然后启动线程

方法:

可以用我们上面的两种方法来实现

方式1:使用继承Thread方法

但是下面类型创造出来多线程会每个线程都吃50个苹果

/**
* 用继承方法来完成吃苹果的多线程需求
*/
//创建一个线程类
class Person extends Thread{
private int num = 50; //构造器,调用Thread的方法赋值
public Person(String name){
super(name);
} public void run(){
for (int i = 0; i < 50; i++) {
if (num > 0){
System.out.println(super.getName()+"吃了编号为"+ num-- +"的苹果");
}
}
}
} public class AppleExtends {
public static void main(String[] args) {
//创建桑个线程
new Person("小A").start();
new Person("小B").start();
new Person("小C").start();
}
}

方式2:使用实现Runnable方式来实现

class Apple implements Runnable{
private int num = 50; public void run(){
for (int i = 0; i < 50; i++) {
if (num > 0){
System.out.println(Thread.currentThread().getName()+"吃了编号为"+ num-- +"的苹果");
}
}
}
} public class appleImplements {
public static void main(String[] args) {
//创建桑个线程
Apple a = new Apple();
new Thread(a,"小A").start();
new Thread(a,"小B").start();
new Thread(a,"小C").start();
}
}

两种方式的区别分析:

继承方式:

1.java中类是单继承的,如果继承了Thread了,该类就不能再有其他的直接父类了

2.从操作上分析,继承方式更简单,获取线程名字也简单(操作上,更简单)

3.从多线程共享一个资源上分析,继承方式不能做到共享

实现接口方式:

1.java中类可以多实现接口,此时该类还可以继承其他类,并且还可以实现其他接口(设计上更优雅)

2.从操作上分析,实现方式稍微复杂点,获取线程名字也稍微复杂,得使用Thread.currentThread()来获取当前线程的引用,使用Thread.currentThread().getname()来获取当前线程的名字

3.从多线程共享一个资源分析,实现方式可以做到共享

第21章 java线程(1)-线程初步的更多相关文章

  1. 《Java并发编程的艺术》 第9章 Java中的线程池

    第9章 Java中的线程池 在开发过程中,合理地使用线程池能带来3个好处: 降低资源消耗.通过重复利用已创建的线程 降低线程创建和销毁造成的消耗. 提高响应速度.当任务到达时,任务可以不需要等到线程创 ...

  2. 第9章 Java中的线程池 第10章 Exector框架

    与新建线程池相比线程池的优点 线程池的分类 ThreadPoolExector参数.执行过程.存储方式 阻塞队列 拒绝策略 10.1 Exector框架简介 10.1.1 Executor框架的两级调 ...

  3. 第23章 java线程通信——生产者/消费者模型案例

    第23章 java线程通信--生产者/消费者模型案例 1.案例: package com.rocco; /** * 生产者消费者问题,涉及到几个类 * 第一,这个问题本身就是一个类,即主类 * 第二, ...

  4. 第22章 java线程(2)-线程同步

    java线程(2)-线程同步 本节主要是在前面吃苹果的基础上发现问题,然后提出三种解决方式 1.线程不安全问题 什么叫线程不安全呢 即当多线程并发访问同一个资源对象的时候,可能出现不安全的问题 对于前 ...

  5. “全栈2019”Java多线程第三十五章:如何获取线程被等待的时间?

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  6. “全栈2019”Java多线程第十五章:当后台线程遇到finally

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  7. 深入理解java虚拟机-第12章Java内存模型与线程

    第12章 Java内存模型与线程 Java内存模型  主内存与工作内存: java内存模型规定了所有的变量都在主内存中,每条线程还有自己的工作内存. 工作内存中保存了该线程使用的主内存副本拷贝,线程对 ...

  8. 《深入理解Java虚拟机》-----第12章 Java内存模型与线程

    概述 多任务处理在现代计算机操作系统中几乎已是一项必备的功能了.在许多情况下,让计算机同时去做几件事情,不仅是因为计算机的运算能力强大了,还有一个很重要的原因是计算机的运算速度与它的存储和通信子系统速 ...

  9. 第24章 java线程(3)-线程的生命周期

    java线程(3)-线程的生命周期 1.两种生命周期流转图 ** 生命周期:**一个事物冲从出生的那一刻开始到最终死亡中间的过程 在事物的漫长的生命周期过程中,总会经历不同的状态(婴儿状态/青少年状态 ...

随机推荐

  1. XAF视频教程来啦,已出7课

        XAF交流学习群内的兄弟录制了视频,他没有博客,委拖我发至博客园,希望能让更多的开发人员受益.快速开发企业级应用的好工具!   XAF入门01快速浏览   XAF入门02特点. XAF入门03 ...

  2. 转载:《TypeScript 中文入门教程》 17、注解

    版权 文章转载自:https://github.com/zhongsp 建议您直接跳转到上面的网址查看最新版本. 介绍 随着TypeScript和ES6里引入了类,现在在一些场景下我们会需要额外的特性 ...

  3. 使用KMP算法判断是否为旋转词

    假设有两个字符串A.B,要判断它们是否为旋转词,只需构造一个"A+A"字符串,再与B比较,若B为A的旋转词,则使用KMP算法是可以得到结果的 代码如下: import java.u ...

  4. zookeeper集群

    0,Zookeeper基本原理 ZooKeeper集群由一组Server节点组成,这一组Server节点中存在一个角色为Leader的节点,其他节点都为Follower.当客户端Client连接到Zo ...

  5. CSS float

    我们来看看CSS重要属性--float. 以下内容分为如下小节: 1:float属性 2:float属性的特性     2.1:float之文字环绕效果 2.2:float之父元素高度塌陷 3:清除浮 ...

  6. MAC 如何使用Github Desktop 客户端

    作为开源代码库以及版本控制系统,Github拥有140多万开发者用户.随着越来越多的应用程序转移到了云上,Github已经成为了管理软件开发以及发现已有代码的首选方法.GitHub上已自动配置的Mac ...

  7. Sanboxie 5.14安装图解

    Sanboxie, 即沙盘,引用官方解释:电脑就像一张纸,程序的运行与改动,就像将字写在纸上.而Sandboxie就相当于在纸上放了块玻璃,程序的运行与改动就像写在了那块玻璃上,除去玻璃,纸上还是一点 ...

  8. iOS之2016面试题三

    1.OC内存管理机制 1).当你使用new,alloc和copy方法创建一个对象时,该对象的保留计数器值为 1.当你不再使用该对象时,你要负责向该对象发送一条release或autorelease消息 ...

  9. Android 四大组件 与 MVC 架构模式

    作为一个刚从JAVA转过来的Android程序员总会思考android MVC是什么样的? 首先,我们必须得说Android追寻着MVC架构,那就得先说一下MVC是个啥东西! 总体而来说MVC不能说是 ...

  10. IOS开发基础知识--碎片16

    1:Objective-C语法之动态类型(isKindOfClass, isMemberOfClass,id) 对象在运行时获取其类型的能力称为内省.内省可以有多种方法实现. 判断对象类型 -(BOO ...