一、基本概念

多线程是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; } }

 

最新文章

  1. Windows 下安装 MongoDB
  2. 移动端web开发的一些知识点
  3. Linux网卡配置及学习linux的注意事项
  4. react使用过程记录
  5. iOS开发小技巧--实现将图片保存到本地相册
  6. Windows下Git安装指南
  7. 部署git服务器 gitServer 软件
  8. android 各国语言对应的缩写
  9. grunt构建前端自动化的开发环境
  10. richTextBox设置选中的字体属性
  11. ORACLE之SQL语句内部解析过程【weber出品】
  12. 软件开发架构介绍||OSI七层协议之物理层、数据链路层、网络层、传输层(mac地址、ip协议、断开协议、tcp协议之三次握手四次挥手)
  13. SpringBoot整合Jsp和Thymeleaf (附工程)
  14. c# WPF RichTextBox 文字颜色
  15. 第三个Sprint ------第五天
  16. Python 正则实现计算器
  17. Android开发 ---如何操作资源目录中的资源文件5 ---Raw资源管理与国际化
  18. C语言的第二次实验报告
  19. Create a Basic Shader in Shader Forge
  20. # HNOI2012 ~ HNOI2018 题解

热门文章

  1. Web后台模拟前端post(带NTLM验证)
  2. RabbitMQ - 介绍
  3. spring整合springmvc和mybatis
  4. golang学习之regexp
  5. jsp、servlet笔记
  6. &lt;td&gt;标签clospan和rowspan 可横跨列数和行数
  7. mockjs
  8. chrome 控制台里 打印对象
  9. Android setTag()/getTag()
  10. icon-font 字体图标的引用