【前面的话】

实际项目在用spring框架结合dubbo框架做一个系统,虽然也负责了一块内容,但是自己的能力还是不足,所以还需要好好学习一下基础知识,然后做一些笔记。希望做完了这个项目可以写一些dubbo框架和spring框架方面的总结。

学习过程中的小知识点总结,基础知识,选择阅读

【线程定义】

在学习操作系统的时候,学习过什么是进程,什么是线程,下面这只维基百科里面关于线程的定义,大家可以看一下:

定义:线程(英语:thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。在Unix System V及SunOS中也被称为轻量进程(lightweight processes),但轻量进程更多指内核线程(kernel thread),而把用户线程(user thread)称为线程。

【实现方法】

1. 第一种继承:Thread类

 class 类名extends Thread{
方法1;
方法2;
……
public void run(){
实现代码
}
}

2. 第二种:实现Runnable接口

 class 类名 implements Runnable{
方法1;
方法2;
……
public void run(){
实现代码
}
}

【三段代码】

第一段代码,就是一个很简单,就是和多线程没有关系的一段测试代码。

第二段代码,使用继承Thread的方法实现多线程。

第三段代码,使用实现Runnable接口的方法实现多线程。

第一段代码:

 public class NoThreadTest {
private String noThread1;
public NoThreadTest(){
}
public NoThreadTest(String noThread1){
this.noThread1=noThread1;
}
public void run(){
for(int i=0;i<3;i++){
System.out.println(noThread1+"非多线程运行结果 "+i);
}
}
public static void main(String[] args){
NoThreadTest maintest1=new NoThreadTest("我是A");
NoThreadTest maintest2=new NoThreadTest("我是B");
maintest1.run();
maintest2.run();
}

执行结果:

 我是A非多线程运行结果                                 0
我是A非多线程运行结果 1
我是A非多线程运行结果 2
我是B非多线程运行结果 0
我是B非多线程运行结果 1
我是B非多线程运行结果 2

第二段代码:

 public class ThreadTest extends Thread {
private String Thread1;
public ThreadTest(){
}
public ThreadTest(String Thread1){
this.Thread1=Thread1;
}
public void run(){
for(int i=0;i<3;i++){//可以参看评论5进行修改,效果会好一些。
System.out.println(Thread1+"多线程运行结果 "+i);
}
}
public static void main(String[] args){
ThreadTest maintest1=new ThreadTest("我是A");
ThreadTest maintest2=new ThreadTest("我是B");
maintest1.run();
maintest2.run();
System.out.println("..............我是分割线........................");
maintest1.start();
maintest2.start();
}
}

执行结果:(每一次执行的结果都是不一样的,这只是其中的某一种)

 我是A多线程运行结果                                 0
我是A多线程运行结果 1
我是A多线程运行结果 2
我是B多线程运行结果 0
我是B多线程运行结果 1
我是B多线程运行结果 2
..............我是分割线........................
我是A多线程运行结果 0
我是B多线程运行结果 0
我是B多线程运行结果 1
我是B多线程运行结果 2
我是A多线程运行结果 1
我是A多线程运行结果 2

第三段代码:

 public class ThreadTest2 implements Runnable {
private String Thread1;
public ThreadTest2(){
}
public ThreadTest2(String Thread1){
this.Thread1=Thread1;
}
public void run(){
for(int i=0;i<3;i++){//可以参看评论5,效果会好一些
System.out.println(Thread1+"多线程运行结果 "+i);
}
}
public static void main(String[] args){
ThreadTest2 maintest1=new ThreadTest2("我是A");
ThreadTest2 maintest2=new ThreadTest2("我是B");
Thread maintest4=new Thread(maintest1);
Thread maintest5=new Thread(maintest2);
maintest1.run();
maintest2.run();
System.out.println("..............我是分割线1........................");
maintest4.run();
maintest5.run();
System.out.println("..............我是分割线2........................");
maintest4.start();
maintest5.start();
}
}

执行结果:(每一次执行的结果都是不一样的,这只是其中的某一种)

 我是A多线程运行结果                                 0
我是A多线程运行结果 1
我是A多线程运行结果 2
我是B多线程运行结果 0
我是B多线程运行结果 1
我是B多线程运行结果 2
..............我是分割线1........................
我是A多线程运行结果 0
我是A多线程运行结果 1
我是A多线程运行结果 2
我是B多线程运行结果 0
我是B多线程运行结果 1
我是B多线程运行结果 2
..............我是分割线2........................
我是B多线程运行结果 0
我是B多线程运行结果 1
我是B多线程运行结果 2
我是A多线程运行结果 0
我是A多线程运行结果 1
我是A多线程运行结果 2

【代码分析】

1. run方法和start方法的区别:

java核心技术中有这样一段话:不要调用Thread类或Runnable对象的run方法。直接调用run方法,只会执行同一个线程中的任务,而不会启动新线程。应该调用Thread.start方法。这个方法将创建一个执行run方法的新线程。

2. 在上面第三段代码中,ThreadTest2类,Thread类和Runnerable接口都实现了run方法。

1)Runnerable接口实现run方法

 public
interface Runnable {
/**
* When an object implementing interface <code>Runnable</code> is used
* to create a thread, starting the thread causes the object's
* <code>run</code> method to be called in that separately executing
* thread.
* <p>
* The general contract of the method <code>run</code> is that it may
* take any action whatsoever.
*
* @see java.lang.Thread#run()
*/
public abstract void run();
}

2)Thread类实现run方法。

 public void run() {
if (target != null) {
target.run();
}
}

3)为什么要说这个?因为这个实现是使用了代理模式。

代理:一个角色代表另一个角色来完成某些特定的功能。

举个例子:大家都买过衣服,所以在买衣服的时候,一般有下面的角色:

购物者:我们一般是从代理商那里买衣服,我们并不和制造商进行交涉,我们不关心衣服是如何生产出来的。

代理商:代理商是从制造商那里拿衣服,并且代理商可以提供一些简单的服务,比如裁剪裤子等。

制造商:制造衣服,并且批发衣服给代理商。

我们从上面的行为中可以抽象出,一个行为就是卖衣服这个行为在代理商和制造商都有,如果购物者要买衣服,也需要以代理商和制造商卖衣服为前提。

从上面我们可以抽象出三个角色,并不是和上面对应的哈。

抽象主题角色:这个使我们可以抽象出来的角色。就是卖衣服这个行为。

代理主题角色:中间商。

实际被代理角色:制造商。

代码:

  • SellClothes.java(需要和接口名一样)
 //抽象主题角色:买衣服
public interface SellClothes {
void sellClothes();
}
  • Middleman.java
 //代理主题角色:中间商
public class Middleman implements SellClothes{
private SellClothes t;
public Middleman(SellClothes t) {
super();
this.t = t;
}
public void sellClothes() {
t.sellClothes();
System.out.println("我是中间商,我买的是制造商的衣服");
System.out.println("我是中间商,我还提供对裤子不合适的进行裁剪服务");
}
}
  • SellClothes.java

 //实际被代理角色
public class Manufacturer implements SellClothes{
public void sellClothes() {
System.out.println("我是制造商,我提供批发衣服服务");
}
}
  • Test.java
 public class Test {
public static void main(String[] args) {
Manufacturer t = new Manufacturer();
Middleman sellclothes = new Middleman(t);
sellclothes.sellClothes();
}
}

运行结果:

 我是制造商,我提供批发衣服服务
我是中间商,我买的是制造商的衣服
我是中间商,我还提供对裤子不合适的进行裁剪服务

    得出结论:

抽象主题角色:Runnable,提供run方法

代理主题角色:Thread类,提供run方法

实际被代理角色:ThreadTest2,也实现了run 方法

这就是代理主题模式,我希望我讲清楚了,哈哈

3. native关键字

在看到start()实现方法的时候,看到了如下一段代码:

   public synchronized void start() {
/**
* This method is not invoked for the main method thread or "system"
* group threads created/set up by the VM. Any new functionality added
* to this method in the future may have to also be added to the VM.
*
* A zero status value corresponds to state "NEW".
*/
if (threadStatus != 0)
throw new IllegalThreadStateException();
group.add(this);
start0();
if (stopBeforeStart) {
stop0(throwableFromStop);
}
}
private native void start0();

然后我好奇,native是什么关键字:

一个Native Method就是一个java调用非java代码的接口。一个Native Method是这样一个java的方法:该方法的实现由非java语言实现

【实现区别】

1. 三段代码

1)第一段:

 public class ThreadTest6 extends Thread {
private int num=3;//定义飞机票的张数
public void run(){
for(int i=0;i<10;i++){
if(num>0){
System.out.println(Thread.currentThread().getName()+"飞机票还剩余num= "+num--);
}
}
}
public static void main(String[] args){
ThreadTest6 threadtest1=new ThreadTest6();
ThreadTest6 threadtest2=new ThreadTest6();
ThreadTest6 threadtest3=new ThreadTest6();
threadtest1.start();
threadtest2.start();
threadtest3.start(); }
}

结果:

 Thread-1飞机票还剩余num= 3
Thread-2飞机票还剩余num= 3
Thread-2飞机票还剩余num= 2
Thread-2飞机票还剩余num= 1
Thread-0飞机票还剩余num= 3
Thread-0飞机票还剩余num= 2
Thread-0飞机票还剩余num= 1
Thread-1飞机票还剩余num= 2
Thread-1飞机票还剩余num= 1

2)第二段:

 public class ThreadTest5 implements Runnable {
private int num=3;//定义飞机票的张数
public void run(){
for(int i=0;i<10;i++){
if(num>0){
System.out.println(Thread.currentThread().getName()+"飞机票还剩余num= "+num--);
}
}
}
public static void main(String[] args){
ThreadTest5 threadtest1=new ThreadTest5();
ThreadTest5 threadtest2=new ThreadTest5();
ThreadTest5 threadtest3=new ThreadTest5();
Thread thread1=new Thread(threadtest1,"窗口1");
Thread thread2=new Thread(threadtest2,"窗口2");
Thread thread3=new Thread(threadtest3,"窗口3");
thread1.start();
thread2.start();
thread3.start();
}
}

结果:

 窗口2飞机票还剩余num= 3
窗口2飞机票还剩余num= 2
窗口2飞机票还剩余num= 1
窗口1飞机票还剩余num= 3
窗口1飞机票还剩余num= 2
窗口1飞机票还剩余num= 1
窗口3飞机票还剩余num= 3
窗口3飞机票还剩余num= 2
窗口3飞机票还剩余num= 1

3)第三段:

 public class ThreadTest7 implements Runnable {
private int num=3;//定义飞机票的张数
public void run(){
for(int i=0;i<10;i++){
if(num>0){
System.out.println(Thread.currentThread().getName()+"飞机票还剩余num= "+num--);
}
}
}
public static void main(String[] args){
ThreadTest7 threadtest1=new ThreadTest7();
Thread thread1=new Thread(threadtest1,"窗口1");
Thread thread2=new Thread(threadtest1,"窗口2");
Thread thread3=new Thread(threadtest1,"窗口3");
thread1.start();
thread2.start();
thread3.start();
}
}

结果:

 窗口1飞机票还剩余num= 3
窗口1飞机票还剩余num= 2
窗口1飞机票还剩余num= 1

2. 分析:

第一和第二段代码不管是使用Runnerable实现还是使用Thread实现,从结果可以看出三个线程每个线程均有num这个资源,如果把num看做是飞机票的话,那么每个线程都有三张飞机票。这不是我们实际中要得到的情况。

      要实现这个飞机售票程序,我们只能创建一个资源对象,但要创建多个线程去处理同一个资源对象,并且每个线程上所运行的是相同的程序代码。

      这就是第三段代码实现的结果,ThreadTest7只创建了一个资源对象——threadtest1。创建了三个线程,每个线程调用的是同一个threadtest1对象中的run()方法,访问的是同一个对象中的变量(num)的实例,这个程序满足了我们的需求。

3. 结论:

可见,实现Runnable接口相对于继承Thread类来说,有如下显著的好处: 
      (1)适合多个相同程序代码的线程去处理同一资源的情况,把虚拟CPU(线程)同程序的代码,数据有效的分离,较好地体现了面向对象的设计思想。 
      (2)可以避免由于Java的单继承特性带来的局限。我们经常碰到这样一种情况,即当我们要将已经继承了某一个类的子类放入多线程中,由于一个类不能同时有两个父类,所以不能用继承Thread类的方式,那么,这个类就只能采用实现Runnable接口的方式了。 
      (3)有利于程序的健壮性,代码能够被多个线程共享,代码与数据是独立的。当多个线程的执行代码来自同一个类的实例时,即称它们共享相同的代码。多个线程操作相同的数据,与它们的代码无关。当共享访问相同的对象是,即它们共享相同的数据。当线程被构造时,需要的代码和数据通过一个对象作为构造函数实参传递进去,这个对象就是一个实现了Runnable接口的类的实例。

【后面的话】

写一篇文章的过程是充满了乐趣的一次奇妙的旅程,有时“柳暗“,有时”花明“。但是当写完的时候如同一次旅行的结束,总会是有收获的。

分享:

  1. 10层以下,走楼梯
  2. 左手刷牙
  3. 公交车读书
  4. 持续早起早睡
  5. 出门的时候记得,“伸手要纸钱“——身份证,手机,钥匙,纸巾,钱包。

——TT

Java学习笔记(八)——java多线程的更多相关文章

  1. Java 学习笔记 (八) Java 变量

    head first java page85 实例变量是声明在类内而不是方法中 class Horse{ private double height=15.2; private String bree ...

  2. Java学习笔记八:Java的流程控制语句之循环语句

    Java的流程控制语句之循环语句 一:Java循环语句之while: 生活中,有些时候为了完成任务,需要重复的进行某些动作.如参加 10000 米长跑,需要绕 400 米的赛道反复的跑 25 圈.在 ...

  3. Java学习笔记八

    IO流:就是input/output输入/输出流. 一.字节流操作文件的便捷类:FileWriter和FileReader import java.io.FileWriter; import java ...

  4. Java学习笔记之—Java基础

    将学习到的JAVA基础用xmind记录了下来,需要原件的可以私信

  5. Java学习笔记--通过java.net.URLConnection发送HTTP请求

    http://www.cnblogs.com/nick-huang/p/3859353.html 使用Java API发送 get请求或post请求的步骤: 1. 通过统一资源定位器(java.net ...

  6. java 学习笔记1 java语言概述及开发环境

    高级语言运行机制 高级语言按程序的执行方式分为编译型和解释型两种. java语言比较特殊,Java程序的执行必须经过先编译后解释的步骤. 1 编译生成字节码,只面向JVM(.class) 2Jvm执行 ...

  7. Java 学习笔记 (三) Java 日期类型

    以下内容摘自:  https://www.cnblogs.com/crazylqy/p/4172324.html import java.sql.Timestamp; import java.text ...

  8. JAVA学习笔记之JAVA 对象引用以及赋值

      关于对象与引用之间的一些基本概念. 初学Java时,在很长一段时间里,总觉得基本概念很模糊.后来才知道,在许多Java书中,把对象和对象的引用混为一谈.可是,如果我分不清对象与对象引用, 那实在没 ...

  9. 8.4(Java学习笔记)java脚本引擎(Rhino)

    一.java脚本引擎 java脚本引擎是沟通java和脚本语句之间的桥梁,可以通过对应的脚本引擎在java中调用各种脚本语言. 二.脚本引擎执行脚本代码 ScriptEngineManager:为Sc ...

  10. Java 学习笔记(4)——java 常见类

    上次提前说了java中的面向对象,主要是为了使用这些常见类做打算,毕竟Java中一切都是对象,要使用一些系统提供的功能必须得通过类对象调用方法.其实Java相比于C来说强大的另一个原因是Java中提供 ...

随机推荐

  1. 洛谷:P2292 [HNOI2004]L语言(DP+Trie树)

    P2292 [HNOI2004]L语言 题目链接:https://www.luogu.org/problemnew/show/P2292 题目描述 标点符号的出现晚于文字的出现,所以以前的语言都是没有 ...

  2. HDU 4576 DP

    Robot Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 102400/102400 K (Java/Others)Total Sub ...

  3. NYOJ 737DP

    石子合并(一) 时间限制:1000 ms  |  内存限制:65535 KB 难度:3   描述     有N堆石子排成一排,每堆石子有一定的数量.现要将N堆石子并成为一堆.合并的过程只能每次将相邻的 ...

  4. Python学习笔记(Django篇)——3、创建第一个数据库模型

    Django里面集成了SQLite的数据库,对于初期研究来说,可以用这个学习.   第一步,创建数据库就涉及到建表等一系列的工作,在此之前,要先在cmd执行一个命令: python manage.py ...

  5. 第01篇 说一下Setting,我一直没有讲过

        settings 调整 settings 中的设置是非常关键的,它们会改变 MyBatis 的运行时行为.下表描述了设置中各项的意图.默认值等. 设置参数 描述 有效值 默认值 cacheEn ...

  6. 51Nod 1009 数字1的个数 | 数位DP

    题意: 小于等于n的所有数中1的出现次数 分析: 数位DP 预处理dp[i][j]存 从1~以j开头的i位数中有几个1,那么转移方程为: if(j == 1) dp[i][j] = dp[i-1][9 ...

  7. 删除linux上7天前后缀名.sql的文件

    #!/bin/bash#delete the file of 7 days agofind /data/mysqlbackup/ -mtime +7 -name "*.sql" - ...

  8. mysql 并发测试

    针对上一节做一些针对公司业务的测试. 我们来做一些压力测试. 服务器配置: 操作系统: centos 5.6-64 CPU: 8核 内存: 8G 硬盘:sas 文件系统:linux MySQL:5.6 ...

  9. 【NOIP】提高组2012 疫情控制

    [题意]n个点的树,1为根,要求删除一些点使得截断根节点和所有叶子结点的路径(不能删根,可以删叶子).有m支军队在m个点上,每时刻所有军队可以走一步,最终走到的地方就是删除的点,求最短时间. [算法] ...

  10. PHP is_null,empty以及isset,unset的区别

    1.empty 判断一个变量是否为“空”.null.false.00.0.’0′.』.为以上值的变量在检测時都将返回true. 2.isset 判断一个变量是否已经设置.0.00.’0′.』.’ ‘. ...