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:类的继承是 ...
随机推荐
- SPOJ - DQUERY(区间不同数+树状数组)
链接:SPOJ - DQUERY 题意:求给定区间不同数的个数(不更新). 题解:离线+树状数组. 对所求的所有区间(l, r)根据r从小到大排序.从1-n依次遍历序列数组,在树状数组中不断更新a[i ...
- 孤荷凌寒自学python第二十三天python类的封装
孤荷凌寒自学python第二十三天python类的封装 (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) 一.从怎么样访问类的内部代码块中定义的私有属性说起 类中定义的私有属性和私有方法是无法被 ...
- pyinstaller打包自己的python程序
使用Pyinstaller打包步骤如下 1. 安装pyinstaller pip install pyinstaller 查看安装的版本 pyinstaller --version 2. 给脚本加密 ...
- 【BZOJ 4151 The Cave】
Time Limit: 5 Sec Memory Limit: 256 MBSec Special JudgeSubmit: 293 Solved: 144[Submit][Status][Di ...
- Eclipse使用Maven内置插件不需要安装Maven
首先修改eclipse项目中maven的路径,默认在C盘,修改路径例如 在d盘创建文件夹-D:- |---m2 |--repository |--setting.xml 没有文件夹和文件要自己新建,如 ...
- Codeforces Round #357 (Div. 2) C
C. Heap Operations time limit per test 1 second memory limit per test 256 megabytes input standard i ...
- Leetcode 4. Median of Two Sorted Arrays(二分)
4. Median of Two Sorted Arrays 题目链接:https://leetcode.com/problems/median-of-two-sorted-arrays/ Descr ...
- ngrepeat 时注意的地方和一些little tricks
angularjs的一些使用经验总结,此篇文章单谈ng指令之一ngrepeat 1. ngrepeat 时报错 Duplicates in a repeater are not allowed, 正常 ...
- HDU2041 简单DP+规律
超级楼梯 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submis ...
- php 计算函数执行时间的方法及获得微妙的方法
// 获得微妙方法 function getMillisecond() { list($s1, $s2) = explode(' ', microtime()); return (float)spri ...