一、基本概念

多线程是Java语言的重要特性,大量应用于网络编程、服务器端程序的开发,最常见的UI界面底层原理、操作系统底层原理都大量使用了多线程。

我们可以流畅的点击软件或者游戏中的各种按钮,其实,底层就是多线程的应用。UI界面的主线程绘制界面,

如果有一个耗时的操作发生则启动新的线程,完全不影响主线程的工作。当这个线程工作完毕后,再更新到主界面上。

我们可以上百人、上千人、上万人同时访问某个网站,其实,也是基于网站服务器的多线程原理。如果没有多线程,服务器处理速度会极大降低。

【程序】

“程序(Program)”是一个静态的概念,一般对应于操作系统中的一个可执行文件,比如:我们要启动酷狗听音乐,则对应酷狗的

可执行程序。当我们双击酷狗,则加载程序到内存中,开始执行该程序,于是产生了“进程”。

【进程】

执行中的程序叫做进程(Process),是一个动态的概念。现代的操作系统都可以同时启动多个进程。比如:我们在用酷狗听音乐,也可以

使用eclipse写代码,也可以同时用浏览器查看网页。进程具有如下特点:

1. 进程是程序的一次动态执行过程, 占用特定的地址空间。

2. 每个进程由3部分组成:cpu、data、code。每个进程都是独立的,保有自己的cpu时间,代码和数据,即便用同一份程序产生好几个进程,

它们之间还是拥有自己的这3样东西,这样的缺点是:浪费内存,cpu的负担较重。

3. 多任务(Multitasking)操作系统将CPU时间动态地划分给每个进程,操作系统同时执行多个进程,每个进程独立运行。以进程的观点来看,

它会以为自己独占CPU的使用权。

4. 进程的查看

【线程】

一个进程可以产生多个线程。同多个进程可以共享操作系统的某些资源一样,同一进程的多个线程也可以

共享此进程的某些资源(比如:代码、数据),所以线程又被称为轻量级进程(lightweight process)。

1. 一个进程内部的一个执行单元,它是程序中的一个单一的顺序控制流程。

2. 一个进程可拥有多个并行的(concurrent)线程。

3. 一个进程中的多个线程共享相同的内存单元/内存地址空间,可以访问相同的变量和对象,而且它们从同一堆中分配对象并进行通信、数据交换和同步操作。

4. 由于线程间的通信是在同一地址空间上进行的,所以不需要额外的通信机制,这就使得通信更简便而且信息传递的速度也更快。

5. 线程的启动、中断、消亡,消耗的资源非常少。

线程和进程的区别:

1. 每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销。

2. 线程可以看成是轻量级的进程,属于同一进程的线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换的开销小。

3. 线程和进程最根本的区别在于:进程是资源分配的单位,线程是调度和执行的单位。

4. 多进程: 在操作系统中能同时运行多个任务(程序)。

5. 多线程: 在同一应用程序中有多个顺序流同时执行。

6. 线程是进程的一部分,所以线程有的时候被称为轻量级进程。

7. 一个没有线程的进程是可以被看作单线程的,如果一个进程内拥有多个线程,进程的执行过程不是一条线(线程)的,而是多条线(线程)共同完成的。

8.  系统在运行的时候会为每个进程分配不同的内存区域,但是不会为线程分配内存(线程所使用的资源是它所属的进程的资源),线程组只

能共享资源。那就是说,除了CPU之外(线程在运行的时候要占用CPU资源),计算机内部的软硬件资源的分配与线程无关,线程只能共享它所属进程的资源。

进程与程序的区别:

    程序是一组指令的集合,它是静态的实体,没有执行的含义。而进程是一个动态的实体,有自己的生命周期。一般说来,一个进程肯定与一个程序相对应

并且只有一个,但是一个程序可以有多个进程,或者一个进程都没有。除此之外,进程还有并发性和交往性。简单地说,进程是程序的一部分,程序运行的时候

会产生进程。

二、Java中的线程

继承Thread类实现多线程的步骤:

1. 在Java中负责实现线程功能的类是java.lang.Thread 类。

2. 可以通过创建 Thread的实例来创建新的线程。

3. 每个线程都是通过某个特定的Thread对象所对应的方法run( )来完成其操作的,方法run( )称为线程体。

4. 通过调用Thread类的start()方法来启动一个线程。

【代码示例】

【创建线程方法一】:继承Thread类+重写run()方法

 /**Thread 多线程
* 创建线程方式一:
* 1、创建:继承Thread类+重写run方法
* 2、创建子类对象,启动线程
*
*/
package cn.sxt.thread; public class Test_0405_Thread extends Thread{
//重写run方法,【线程】入口点
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("一边听歌"); }
}
public static void main(String[] args) {
//启动线程: 就是要创建一个子类对象
Test_0405_Thread thread=new Test_0405_Thread();//创建一个子类对象
thread.start();//启动线程,start()方法 开启一个线程,start(),自己会调run(),交给cpu去调用run()方法,但是main方法不会停止
//继续往下走由于cpu调用run方法回来时间不一定,输出结果可能是“听歌”与“敲代码”混合的,也可能先敲代码后听歌. //thread.run(); 若把上句换成这个直接调用run(),由于run()就是一普通方法,所以cpu肯定先调完run(),它再执行下边的语句 for (int i = 0; i < 10; i++) {
System.out.println("一边敲代码"); } } }
/**线程使用示例:从一个网站下载多张图片,同时下载
*
*
*/
package cn.sxt.thread; import java.io.File;
import java.io.IOException;
import java.net.URL;
import org.apache.commons.io.FileUtils; public class Test_0405_WebDownload extends Thread { public static void main(String[] args) {
ThreadDown t1=new ThreadDown("https://www.baidu.com/img/bd_logo1.png", "src_dest/baidu.jpg");
ThreadDown t2=new ThreadDown("https://wx1.sinaimg.cn/mw690/775d10bdgy1g1u10vajc3j20k00d20u6.jpg", "src_dest/haimian.jpg"); t1.start();
t2.start();//2个线程独立,t1.start();先开始不一定它先结束
} }
//多线程下载类
class ThreadDown extends Thread{
private String url;
private String name; public ThreadDown(String url, String name) {
super();
this.url = url;
this.name = name;
}
//下载方法 拷贝网络地址上"url"的一张图片到 文件"name"
public void download(String url_1,String name_1) throws IOException {
FileUtils.copyURLToFile(new URL(url_1), new File(name_1));
} public void run() {
try {
download(url, name);
System.out.println(name);//可以看出2张图片的下载并没有先后顺序t1.start();先开始但它不一定先下载完
} catch (IOException e) {
System.out.println("链接不合法!");
} } }

【创建线程方法二】 Runnable接口

/***
* 创建线程方法二:实现Runnable接口(推荐),避免单继承的局限性,方便共享资源
* 1、实现runnable接口+重写run
* 2、启动 :创建实现类对象+创建代理类对象 +start
*/
package cn.sxt.thread; public class Test_0405_Runnable implements Runnable {//1-1:实现接口
public void run() {//1-2:重写run()方法
System.out.println("听歌"); } public static void main(String[] args) {
/* //2-1:创建实现类对象
Test_0405_Runnable tRunnable=new Test_0405_Runnable();
//2-2:创建代理类对象,丢入实现类对象tRunnable
Thread thread=new Thread(tRunnable);
//2-3:启动start
thread.start(); */ //合3为1, 创建匿名对象
new Thread( new Test_0405_Runnable() ).start();//调用run方法去了,不知什么时候回来,主方法继续往下不等它 System.out.println("敲代码"); }
}

【练习接口】

/**练习Runnable  共享资源 ,会并发的问题,出现了负数 ,如何保证数据准确?下面的问题要保证线程安全,即数据准确
*12306 抢票和龟兔赛跑;
*
*/
package cn.sxt.thread; public class Test_0405_RunnableTest { public static void main(String[] args) {
/* //1份资源 web,多个代理 3个黄牛
Web12306 web=new Web12306();
System.out.println(Thread.currentThread().getName());//主方法的线程 输出“main” //start()表示web对象调用run方法去了,不知什么时候回来,主方法继续往下不等它.又来个线程也去调用run方法去了
new Thread(web,"李白").start();//3个线程相互独立
new Thread(web,"杜甫").start();
new Thread(web,"王维").start(); System.out.println("在局子里等你!");*/ Racer racer1=new Racer();
//Racer racer2=new Racer();
new Thread(racer1,"兔兔").start();
new Thread(racer1,"乌龟").start();
}
}
//模拟12306 抢票
class Web12306 implements Runnable{
private int ticketNum=10; public void run() {
while (true) {
if (ticketNum<1) {
System.out.println("没有余票了!");
break;
}
try { //模拟网络延时 200毫秒延时
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
} //Thread.currentThread().getName(),当前线程的名字,谁运行就输出谁的名字
System.out.println(Thread.currentThread().getName()+"->"+ticketNum--);
}
}
} //模拟龟兔赛跑:其实是2个进程谁先抢到1份资源就是50这个数字,谁就赢。
class Racer implements Runnable{
private String winner; //比赛过程
public void run() {
for (int step = 1; step <=50; step++) {//步数
//模拟兔子休息,每5步休息一下 run()方法不能throw异常只能try-catch
if (Thread.currentThread().getName().equals("兔兔")&&step%5==0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
} if (Thread.currentThread().getName().equals("兔兔")) {
System.out.println(Thread.currentThread().getName()+"->"+step);
}else {
System.out.println(Thread.currentThread().getName()+"--->"+step);
} boolean flag=gameOver(step);//当前线程每走一步看下比赛是否结束
if (flag==true) {//如果返回值为真,说明比赛已经结束,则跳出循环。如果没有继续循环
break;
}
}
}
//判断比赛是否结束 没结束返回为假
private boolean gameOver(int steps){
if (winner!=null) {
return true; } else {
if (steps==50) {
winner=Thread.currentThread().getName();
System.out.println("胜利者是:"+winner);
return true;
}
}
return false; } }

 

[19/04/05-星期五] 多线程_Thread(线程、线条)、基本术语的更多相关文章

  1. Java中线程的使用 (2)-多线程、线程优先级、线程睡眠、让步、阻塞

    Java中线程的使用 (2)-多线程.线程优先级.线程睡眠.让步.阻塞 (一)多线程使用方法 说明:创建每个新的线程,一定要记得启动每个新的线程(调用.start()方法) class Xc3 ext ...

  2. JAVA多线程之线程间的通信方式

    (转发) 收藏 记 周日,北京的天阳光明媚,9月,北京的秋格外肃穆透彻,望望窗外的湛蓝的天,心似透过栏杆,沐浴在这透亮清澈的蓝天里,那朵朵白云如同一朵棉絮,心意畅想....思绪外扬, 鱼和熊掌不可兼得 ...

  3. Java多线程之线程的生命周期

    Java多线程之线程的生命周期 一.前言 当线程被创建并启动以后,它既不是一启动就进入了执行状态,也不是一直处于执行状态.在线程的生命周期中,它要经过新建(New).就绪(Runnable).运行(R ...

  4. Ubuntu 19.04

    Ubuntu 19.04自动挂载机械盘 创建要挂载的文件夹 sudo mkdir /home/soldier/SOLDIER 获取UUID sudo blkid 分区的TYPE是“ntfs” 编辑/e ...

  5. Python多线程_thread和Threading

    目录 多线程 _thread模块 使用 _thread模块创建线程 threading 使用 threading模块创建线程 线程同步 在讲多线程之前,我们先看一个单线程的例子: import _th ...

  6. C#多线程之线程池篇3

    在上一篇C#多线程之线程池篇2中,我们主要学习了线程池和并行度以及如何实现取消选项的相关知识.在这一篇中,我们主要学习如何使用等待句柄和超时.使用计时器和使用BackgroundWorker组件的相关 ...

  7. C#多线程之线程池篇2

    在上一篇C#多线程之线程池篇1中,我们主要学习了如何在线程池中调用委托以及如何在线程池中执行异步操作,在这篇中,我们将学习线程池和并行度.实现取消选项的相关知识. 三.线程池和并行度 在这一小节中,我 ...

  8. C#多线程之线程池篇1

    在C#多线程之线程池篇中,我们将学习多线程访问共享资源的一些通用的技术,我们将学习到以下知识点: 在线程池中调用委托 在线程池中执行异步操作 线程池和并行度 实现取消选项 使用等待句柄和超时 使用计时 ...

  9. C#多线程之线程同步篇3

    在上一篇C#多线程之线程同步篇2中,我们主要学习了AutoResetEvent构造.ManualResetEventSlim构造和CountdownEvent构造,在这一篇中,我们将学习Barrier ...

随机推荐

  1. 7、srpingboot改变JDK版本

    在pom.xml中加上 <plugin> <artifactId>maven-compiler-plugin</artifactId> <configurat ...

  2. jxls实现基于excel模板的报表

    此文章是基于 搭建Jquery+SpringMVC+Spring+Hibernate+MySQL平台 一. jar包介绍 1. commons-collections-3.2.jar 2. commo ...

  3. hdu 1011 树形背包

    http://blog.csdn.net/libin56842/article/details/9876503 这道题和poj 1155的区别是: poj1155是边的价值,所以从边的关系入手 hdu ...

  4. C Primer Plus note1

    C语言编译错误:multiple definition of `main' main多重定义,在同一个工程中定义了多个main函数 出现如下图的错误: 这是因为在第一张图中,有一个main.c的mai ...

  5. jquery点击导航栏选中更换样式

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  6. php编程--二叉树遍历算法实现

    今天使用php来实现二叉树的遍历 创建的二叉树如下图所示 php代码如下所示:   <?php   class Node {   public $value;   public $child_l ...

  7. framework7的改进,以及与vue组合使用遇到的问题以及解决方法 (附vue的原理)

    framework7官方提供了vue+framework7的组合包,但是那个包用起来复杂度较高,而且不灵活.听说bug也不少. 所以我想用最原始的方式单独使用vue和framework7. 遇到以下问 ...

  8. Python-常用模块1

    今天我们来看一看python中的常用的模块,内容有点多,我会分两天来更新这些知识 一.什么是模块 模块就是我们把装有特定功能的代码就行归类的结果,从代码编写的单位来看我们的程序,从小到大的顺序:一条代 ...

  9. orcale数据恢复

    在操作数据时,不小心改错了表中的数据,想恢复到之前的数据,则可用以下方法: 1.首先我们需要通过dbms_flashback.get_system_change_number,它可以获取系统当前的SC ...

  10. Java 反射、注解

    1. 泛型 基本用法.泛型擦除.泛型类/泛型方法/泛型接口.泛型关键字.反射泛型! a. 概述 泛型是JDK1.5以后才有的, 可以在编译时期进行类型检查,且可以避免频繁类型转化! // 运行时期异常 ...