2.1多线程(java学习笔记) java中多线程的实现(附静态代理模式)
一、多线程
首先我们要清楚程序、进程、线程的关系。
首先进程从属于程序,线程从属于进程。
程序指计算机执行操作或任务的指令集合,是一个静态的概念。
但我们实际运行程序时,并发程序因为相互制约,具有“执行——暂停——执行”的状态,
显然这时程序这个静态的概念无法描述这种状态,从而人们引入了进程这个动态的概念分析研究程序的活动。
目前国内对进程的定义:进程是指一个具有一定独立功能的程序关于某个数据集合的一次运行活动。
而线程从属于进程,线程是比进程更小的活动单位,它是进程中的一个执行路径。一个进程可以有多个执行路径,即多线程。
二、java中多线程的实现
1. 继承Thread实现多线程
public class TestThread {
public static void main(String args[]){
Thre t1 = new Thre("线程1");
Thre t2 = new Thre("线程2");
t1.start(); //多线程的调用并不是直接调用重写之后run方法
t2.start(); //而是通过start调用,start方法通过调用操作系统中的函数来实现资源的分配
} //但实质是调用的还是run方法,只是中间通过了start方法。 }
class Thre extends Thread{ //要实现多线程需继承Thread类,并重写Thread中的run方法。
private int i; //run方法称为线程主体,是多线程运行时执行的部分。
private String name; public Thre(String name){
this.name = name; } public void run(){
for(i = 0; i < 10; i++){
System.out.println(name +": "+ i);
}
}
}
运行结果:
线程2: 0
线程1: 0
线程2: 1
线程1: 1
线程2: 2
线程2: 3
线程2: 4
线程2: 5
线程1: 2
线程1: 3
线程1: 4
线程1: 5
线程1: 6
线程1: 7
线程1: 8
线程1: 9
线程2: 6
线程2: 7
线程2: 8
线程2: 9
可以看到最后的运行结果,是两个线程“同时”运行的,这里的同时是一种宏观上同时处理两个线程,但它们实质是是交替运行的的。
这个举个例子,比如通信运营商要同时提供20个人通话,可以把一秒划分成1000ms,把第1、21、41.....(以此类推)ms给第一个用户使用,第2、22、42...ms给第二个用户使用
由于间隔时间很短,用户察觉不到其中的间隔看起来像是连续的。从微观上看每一个ms只能服务一个用户,从宏观上来看是同时服务了20个用户。
因为分时系统采用时间片轮转的方法来处理多线程,由于一个时间片很短,所以看起来像是同时运行。
2.通过实现Runable接口来实现多线程
在用接口实现多线程之前,需要了解一种模式:
静态代理模式:
静态代理模式实现的条件:
2.1.真实角色
2.2代理角色:(代理角色中还需要引用真实角色)
2.3两者实现相同的接口
下面我们举个例子
public class Test{
public static void main(String[] args) {
My my = new My();
MarryCompany user_my = new MarryCompany(my);//代理角色引用真实角色。
user_my.marry(); //最后结婚的是自己,但可以使用代理角色提供的服务。
}
} interface Marry{ //结婚功能的接口
public void marry();
} class My implements Marry{ //my是真实角色,要实现结婚接口 @Override
public void marry() {
System.out.println("my 结婚");
}
} class MarryCompany implements Marry{ //婚庆公司是代理角色也要实现结婚接口
private Marry user; //代理角色对真实角色的引用,首先在代理角色中创建真实角色。
public MarryCompany(Marry user){
this.user = user;
} private void deadWork_1(){ //代理角色提供的一些服务(方法)。
System.out.println("准备工作1");
} private void deadWork_2(){
System.out.println("准备工作2");
} @Override
public void marry() { //代理角色中实现接口的方法。
deadWork_1(); //代理角色提供的方法。
deadWork_2();
user.marry(); //真实角色结婚
}
}
运行结果:
准备工作1
准备工作2
my 结婚
就相当于与你要结婚,可以委托婚庆公司,这就是把代理角色引用真实角色(My my = new My();
MarryCompany user_my = new MarryCompany(my);)最后是让婚庆公司代理一些事务,但最后结婚的还是自己。
真实对象可以使用代理对象的一些方法,也可以说代理对象帮我做一些事情。
和房产中介也是一样的,我们可以让代理角色(中介)帮我们提供一些它拥有的(方法)资源。
但买房的还是我们自己。
接着我们来看接口实现多线程,接口实现多线程也是使用的代理模式。
首先回一下代理模式的三个条件
1.真实对象
2.代理对象(代理对象引用真实对象)
3.实现相同的接口
我们来看下Thread这个类的源码
会发现Thread这个类实现了Runable接口。
而Runable接口中有run方法。
同时Thread提供了各种构造方法传递真实对象。(Runable接口作为类型)
所以我们用接口实现多线程还需要如下步骤:
1.真实角色(实现Runable接口)
2.代理角色(引用真实角色,代理角色是Thread类)
public class TestThread {
public static void main(String args[]){
Thre t1 = new Thre("线程1"); //创建真实角色,并分配一个名称便于查看
Thre t2 = new Thre("线程2");
Thread p_t1 = new Thread(t1); //代理角色对真实角色的引用
Thread p_t2 = new Thread(t2);
p_t1.start(); //通过代理启动多线程,但实质上运行的还是真实角色。
p_t2.start();
} } class Thre implements Runnable{
private int i;
private String name; public Thre(String name){
this.name = name; } public void run(){
for(i = 0; i < 10; i++){
System.out.println(name +": "+ i);
}
}
}
运行结果:
线程1: 0
线程2: 0
线程1: 1
线程2: 1
线程1: 2
线程1: 3
线程1: 4
线程2: 2
线程2: 3
线程2: 4
线程2: 5
线程2: 6
线程2: 7
线程2: 8
线程2: 9
线程1: 5
线程1: 6
线程1: 7
线程1: 8
线程1: 9
一般建议使用接口实现多线程:
1.用接口实现多线程可以避免单继承的局限性。
比如我有一个类要一定要继承别的类,那么就无法通过继承Thread来实现多线程了。
2.可以资源共享
这里举个例子,比如抢票。票的总数应该是被所以线程(用户)共享的。
我们用传统的继承实现多线程来模拟简易抢票:
public class TestThread {
public static void main(String[] args) {
My_12306 user1 = new My_12306("用户");
My_12306 user2 = new My_12306("黄牛");
user1.start();
user2.start();
}
} class My_12306 extends Thread {
private int ticket = 5;
private String name; public My_12306(String name){
this.name = name;
} public void run(){
for(int i = 0; i < 100; i++){
if(ticket > 0)
System.out.println(name +"抢到了"+ ticket-- +"号票!");
}
}
}
运行结果:
黄牛抢到了5号票!
用户抢到了5号票!
黄牛抢到了4号票!
用户抢到了4号票!
用户抢到了3号票!
用户抢到了2号票!
用户抢到了1号票!
黄牛抢到了3号票!
黄牛抢到了2号票!
黄牛抢到了1号票!
可以发现两个线程间的资源是独立的,每个用户都有5张票。
结合下图理解
如果我们用接口实现多继承来模拟抢票
public class TestThread {
public static void main(String[] args) {
My_12306 m12306 = new My_12306(); Thread user_1 = new Thread(m12306,"用户");
Thread user_2 = new Thread(m12306,"黄牛");
user_1.start();
user_2.start();
}
} class My_12306 implements Runnable {
private int ticket = 10;
private String name; public My_12306(){} public My_12306(String name){
this.name = name;
} public void run(){
for(int i = 0; i < 100; i++){
if(ticket > 0){
System.out.println(Thread.currentThread().getName() +"抢到了"+ ticket-- +"号票!");
}
}
}
}
运行结果:
用户抢到了10号票!
黄牛抢到了10号票!
黄牛抢到了9号票!
用户抢到了8号票!
用户抢到了6号票!
用户抢到了5号票!
用户抢到了4号票!
用户抢到了3号票!
用户抢到了2号票!
用户抢到了1号票!
黄牛抢到了7号票!
可以看到用接口实现多线程可以实现资源共享,第10号票同时被用户和黄牛抢走,
这是因为线程执行速度太快,资源又没有同步导致的,这就涉及到后面的同步问题。
结合下图理解
2.1多线程(java学习笔记) java中多线程的实现(附静态代理模式)的更多相关文章
- [java学习笔记]java语言核心----面向对象之this关键字
一.this关键字 体现:当成员变量和函数的局部变量重名时,可以使用this关键字来区别:在构造函数中调用其它构造函数 原理: 代表的是当前对象. this就是所在函数 ...
- [java学习笔记]java语言核心----面向对象之构造函数
1.构造函数概念 特点: 函数名与类名相同 不用定义返回值类型 没有具体的返回值 作用: 给对象进行初始化 注意: 默认构造函数 多个构造函数是以重载出现的 一个类中如果 ...
- java学习笔记-继承中super关键字
背景: 在java继承的概念中我们得知,被声明为私有的类成员对所属的类来说仍然是私有的.类之外的任何代码都不能访问,包括子类. super关键字的两种用法: 1.用于调用超类的构造函数: 2.用于访问 ...
- Java学习笔记4(多线程)
多线程 多个程序块同时运行的现象被称作并发执行.多线程就是指一个应用程序中有多条并发执行的线索,每条线索都被称作一条线程,它们会交替执行,彼此间可以进行通信. 进程:在一个操作系统中,每个独立执行的程 ...
- Java学习笔记-Java中的常用类
Java中有很多类是很常用的,此处列举System,Runtime,Date,Calendar,Math System System:类中的方法和属性都是静态的 字段摘要 static PrintSt ...
- Java学习笔记_网络+多线程
支持同时收发的客户端和服务器端 客户端 import javax.swing.*; import java.awt.*; import java.io.*; import java.net.*; im ...
- Java学习笔记 -- Java定时调度工具Timer类
1 关于 (时间宝贵的小姐姐请跳过) 本教程是基于Java定时任务调度工具详解之Timer篇的学习笔记. 什么是定时任务调度 基于给定的时间点,给定的时间间隔或者给定的执行次数自动执行的任务. 在Ja ...
- [Java学习笔记] Java异常机制(也许是全网最独特视角)
Java 异常机制(也许是全网最独特视角) 一.Java中的"异常"指什么 什么是异常 一句话简单理解:异常是程序运行中的一些异常或者错误. (纯字面意思) Error类 和 Ex ...
- 我的Java学习笔记-Java面向对象
今天来学习Java的面向对象特性,由于与C#的面向对象类似,不需详细学习 一.Java继承 继承可以使用 extends 和 implements 这两个关键字来实现继承. extends:类的继承是 ...
随机推荐
- FluentAPI深入
1. HasMaxLenght 设定字段得最大长度: static void Main(string[] args) { using (TestDbContext ctx = new TestDbC ...
- 1094 The Largest Generation (25 分)(树的遍历)
求结点最多的一层 输出该层的结点个数以及层号 #include<bits/stdc++.h> using namespace std; vector<]; map<int,in ...
- python中os.path.join和join的区别
这两个函数都是python的系统函数,都有“组合”.“连接”之意,但用法和应用场景千差万别 函数说明: 1.join函数 用法:用于连接字符串数组.将字符串.元组.列表中的元素以指定的字符(即分隔符) ...
- Spring 笔记(四)AOP
前言 横切关注点 使用 @AspectJ 定义切面. 同时还需要在配置类上应用 @EnableAspectJAutoProxy 注解,启用 AOP 自动代理.(不添加它的话,@AspectJ 注解的类 ...
- hadoop-eclipse环境搭建(二)
Eclipse插件配置 第一步:把我们的"hadoop-eclipse-plugin-1.0.0.jar"放到Eclipse的目录的"plugins"中,然后重 ...
- Linux下nginx支持.htaccess文件实现伪静态的方法!
在Google上搜索的资料很多人都说nginx目前不支持.htaccess文件,我按照nginx的规则试验了一下,结果发现nginx是完全支持.htaccess文件的! 方法如下: 1. 在需要使用. ...
- 存储 磁盘大于2TB 大数据存储一个盘 解决方法
1.vmware虚拟机环境下可以做裸映射 但是一个存储 只能对应一个虚拟主机裸映射 我已经在一个10TB的存储上做好多个主机,就不适用了 2.在虚拟机上添加5个2TB磁盘,磁盘管理中新建 带区卷 可以 ...
- [poj] 2749 building roads
原题 2-SAT+二分答案! 最小的最大值,这肯定是二分答案.而我们要2-SATcheck是否在该情况下有可行解. 对于目前的答案limit,首先把爱和恨连边,然后我们n^2枚举每两个点通过判断距离来 ...
- POJ 3977 Subset | 折半搜索
题目: 给出一个整数集合,求出非空子集中元素和绝对值最小是多少(元素个数尽量少) 题解: 分成两半 爆搜每一半,用map维护前一半的值 每搜出后一半的一个值就去map里找和他和绝对值最小的更新答案 # ...
- ubuntu安装出现"删除initramfs-tools时出错",subprocess installed post-installation script returned error exit status 1
昨日准备重装ubuntu,增大了系统容量,因为前面用到boot分区不到100M,于是这里分区如下 /boot 100M / 30G /home 50G 然后安装快结束时就出现如下图问题 开始以为是镜像 ...