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:类的继承是 ...
随机推荐
- Python全栈工程师
ParisGabriel Python 入门基础 print(“hello world”)变量 : 存储信息的,日后被调用.修改操作常量: 固定不变的量,字母大写命名规则:1. 字母数 ...
- Ext JS 的一个非常好的学习网站
起飞网 http://www.qeefee.com/zt-extjs 发现一个非常好的学习ExtJS的中文网站
- Linq学习(一)
与LINQ有关的语言特性 1.隐式类型 var 2.匿名类型 如:var obj = new {Guid.Empty, myTitle = "匿名类型", myOtherParam ...
- 【bzoj4822/bzoj1935】[Cqoi2017]老C的任务/[Shoi2007]Tree 园丁的烦恼 树状数组
原文地址:http://www.cnblogs.com/GXZlegend/p/6825530.html bzoj4822 题目描述 老 C 是个程序员. 最近老 C 从老板那里接到了一个任务 ...
- 2017 多校4 Matching In Multiplication(二分图)
Matching In Multiplication 题解: 首先如果一个点的度数为1,那么它的匹配方案是固定的,继而我们可以去掉这一对点.通过拓扑我们可以不断去掉所有度数为1的点. 那么剩下的图中左 ...
- BZOJ4825 [Hnoi2017]单旋 【线段树】
题目链接 BZOJ4825 题解 手模一下操作,会发现一些很优美的性质: 每次旋到根,只有其子树深度不变,剩余点深度\(+1\) 每次旋到根,[最小值为例]右儿子接到其父亲的左儿子,其余点形态不改变, ...
- uoj169:元旦老人与数列
题意:http://uoj.ac/problem/169 sol :线段树..........蜜汁TLE了一个点,不管了..... 代码抄snowMyDream的,orz........... 线段 ...
- java中的UDP总结
先说一下关于InetAddress类,用一个小例子: import java.net.InetAddress; import java.net.UnknownHostException; public ...
- 使用jdk中的java.sql包中的方法进行jdbc连接
首先说明用 java.sql包进行jdbc连接的步骤: 1.加载数据库的驱动.(一般是oracle和mysql,oracle的数据驱动名是:Oracle.jdbc.driver.OracleDrive ...
- 百度之星初赛(A)——T2
数据分割 小w来到百度之星的赛场上,准备开始实现一个程序自动分析系统. 这个程序接受一些形如x_i = x_jxi=xj 或 x_i \neq x_jxi≠xj 的相等/不等约 ...