概述

进程:

是一个正在执行中的程序

每一个进程执行都有一个执行顺序,该执行顺序是一个执行路径,或者叫一个控制单元

线程:

就是进程中的一个独立的控制单元,线程在控制着进程的执行

一个进程中至少有一个线程

Java JVM启动的时候会有一个进程java.exe,该进程中至少有一个线程负责Java程序的执行,而且这个线程运行的代码存在于main方法中,该线程称之为主线程,与C类似,java.exe相当于所有进程的父进程,而且JVM启动了不止一个线程,还有负责垃圾回收的线程

创建线程

第一种创建方式:继承Thread类

   1: class Sell extends Thread

   2: {

   3:     private int tickets = 100;

   4:     Sell()

   5:     {

   6:         //启动线程

   7:         start();

   8:     }

   9:     //复写Thread类中的run方法,将线程运行所需的代码写到run方法中

  10:     public void run()

  11:     {

  12:         while(tickets > 0)

  13:         {

  14:             System.out.println("tickets = "+tickets--);

  15:         }

  16:     }

  17: }

第二种创建方式:实现Runnable接口

   1: class Sell implements Runnable

   2: {

   3:     private int tickets = 100;

   4:     

   5:     //实现Runnable接口的run方法

   6:     public void run()

   7:     {

   8:         while(tickets > 0)

   9:         {

  10:             System.out.println("tickets = "+tickets--);

  11:         }

  12:     }

  13: }

  14: class ThreadDemo 

  15: {

  16:     public static void main(String[] args) 

  17:     {

  18:         //将Runnable接口的子类Sell传递给Thread的构造函数,并启动线程

  19:         new Thread(new Sell()).start();

  20:     }

  21: }

实现方式与继承方式的区别

其实Thread类同样也是实现了Runnable接口,所以我们要的只是run方法,那么我们只要实现Runnable接口即可,这样避免了单继承的局限性,我们在实现Runnable接口的同时还可以继承其他的类,扩展了功能

线程权限问题

线程安全问题--同步

当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程参与进来执行,导致共享数据的错误

   1:  

   2: class Sell implements Runnable

   3: {

   4:     private int tickets = 10;

   5:     

   6:     //实现Runnable接口的run方法

   7:     public void run() 

   8:     {

   9:         while(tickets > 0)

  10:         {

  11:             try{Thread.sleep(500);}catch(Exception e){}

  12:             System.out.println(Thread.currentThread().getName()+"..tickets = "+(--tickets));

  13:         }

  14:     }

  15: }

当我们让线程操作共享数据时,暂停一会,可以发现,每个线程很容易-1剩余票数的错误

解决方法

对多条操作共享数据的语句,只能让一个线程都执行完,在执行过程中,其他线程不能参与进来执行

Java对多线程的安全问题提供了专业的解决方式,就是同步代码块或者同步函数

synchronized(对象)

{

需要被同步的代码

}

synchronized void show()

{

函数内容

}

   1: class Sell implements Runnable

   2: {

   3:     private int tickets = 10;

   4:     

   5:     //实现Runnable接口的run方法

   6:     public void run() 

   7:     {

   8:         //加入锁,使代码同步

   9:         synchronized(this)

  10:         {

  11:             while(tickets > 0)

  12:             {

  13:                 try{Thread.sleep(500);}catch(Exception e){}

  14:                 System.out.println(Thread.currentThread().getName()+"..tickets = "+(--tickets));

  15:             }

  16:         }

  17:     }

  18: }

我们可以看到,即使中途有睡眠过程,也不再出现错误票数,当然这个例子有一些问题,虽然保证了安全,却只能让一个线程完成操作,解决方法很简单,在while循环内设置判断语句,再加锁即可

对象如同锁,持有锁的线程可以在同步中执行

没有持有锁的线程即使获取了cpu的执行权,也无法执行同步代码

如果同步函数被静态修饰后,如何使用锁?

通过验证,发现不再是this,因为静态方法中也不可以定义this

静态进入内存时,内存中没有本类对象,但是一定有该类的对应的字节码文件对象 类名.class,该对象的类型是Class

所以静态的同步方法是,使用该方法所在类的字节码对象作为锁,即类名.class

   1: class Tickets

   2: {

   3:     static int tickets = 10;

   4:     public static void sell()

   5:     {

   6:         //类对象作为锁

   7:         synchronized(Selling.class)

   8:         {

   9:             if(tickets > 0)

  10:             {

  11:                 try{Thread.sleep(500);}catch(Exception e){}

  12:                 System.out.println(Thread.currentThread().getName()+"..tickets = "+(--tickets));

  13:             }

  14:         }

  15:     }

  16: }

  17:  

  18: class Selling implements Runnable

  19: {

  20:     //实现Runnable接口的run方法

  21:     public void run() 

  22:     {

  23:         while(Tickets.tickets> 0)

  24:         {

  25:             Tickets.sell();

  26:         }    

  27:     }

  28: }

同步的前提:

  1. 必须要有两个或两个以上的线程

  2. 必须要多个线程使用同一个锁

同步的利弊

好处:解决了多线程的安全问题

弊端:多个线程需要判断锁,较为消耗资源

加入同步之后线程的状态如下

如何编写多线程

  1. 明确哪些代码是多线程运行代码

  2. 明确共享数据
  3. 明确多线程运行代码中哪些语句是操作共享数据的

死锁

死锁其实就是同步中嵌套同步

   1:  

   2: class A implements Runnable

   3: {

   4:     String a = "a";

   5:  

   6:     public void run()

   7:     {

   8:         while(true)

   9:         {

  10:             //A抢占A锁

  11:             synchronized(A.class)

  12:             {

  13:                 System.out.println("A get 1");

  14:                 //A抢占B锁

  15:                 synchronized(B.class)

  16:                 {

  17:                     System.out.println("A get 2");

  18:                     System.out.println("A:"+a);

  19:                 }

  20:             }

  21:         }

  22:     }

  23: }

  24:  

  25: class B implements Runnable

  26: {

  27:     String b = "b";

  28:  

  29:     public void run()

  30:     {

  31:         while(true)

  32:         {

  33:             //B抢占B锁

  34:             synchronized(B.class)

  35:             {

  36:                 System.out.println("B get 1");

  37:                 //B抢占A锁

  38:                 synchronized(A.class)

  39:                 {

  40:                     System.out.println("B get 2");

  41:                     System.out.println("B:"+b);

  42:                 }

  43:             }

  44:         }

  45:     }

  46: }

  47: class DeadlockDemo 

  48: {

  49:     public static void main(String[] args) 

  50:     {

  51:         new Thread(new A()).start();

  52:         new Thread(new B()).start();

  53:     }

  54: }

结果如下,A和B都在等待对方释放资源(对应的锁)

Java笔记(十九)……多线程的更多相关文章

  1. python3.4学习笔记(十九) 同一台机器同时安装 python2.7 和 python3.4的解决方法

    python3.4学习笔记(十九) 同一台机器同时安装 python2.7 和 python3.4的解决方法 同一台机器同时安装 python2.7 和 python3.4不会冲突.安装在不同目录,然 ...

  2. “全栈2019”Java第九十九章:局部内部类与继承详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  3. “全栈2019”Java第二十九章:数组详解(中篇)

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  4. “全栈2019”Java第十九章:关系运算符、条件运算符和三元运算符

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  5. (C/C++学习笔记) 十九. 模板

    十九. 模板 ● 模板的基本概念 模板(template) 函数模板:可以用来创建一个通用功能的函数,以支持多种不同形参,进一步简化重载函数的函数体设计. 语法: template <<模 ...

  6. Java基础学习笔记十九 IO

    File IO概述 回想之前写过的程序,数据都是在内存中,一旦程序运行结束,这些数据都没有了,等下次再想使用这些数据,可是已经没有了.那怎么办呢?能不能把运算完的数据都保存下来,下次程序启动的时候,再 ...

  7. Java基础学习笔记十九 File

    IO概述 回想之前写过的程序,数据都是在内存中,一旦程序运行结束,这些数据都没有了,等下次再想使用这些数据,可是已经没有了.那怎么办呢?能不能把运算完的数据都保存下来,下次程序启动的时候,再把这些数据 ...

  8. Java学习笔记十九:Java中的访问控制修饰符

    Java中的访问控制修饰符 一:Java修饰符的种类: 访问修饰符 非访问修饰符 修饰符用来定义类.方法或者变量,通常放在语句的最前端.我们通过下面的例子来说明: public class Hello ...

  9. swift 笔记 (十九) —— 协议

    协议(Protocols) 协议仅是用定义某些任务或者是功能必须的方法和属性. 类似于java里的interface的作用.但协议并不会实现详细的功能. 我猜这个名字源于OO中提到的"契约& ...

随机推荐

  1. LBS地理位置距离计算方法之geohash算法

    随着移动终端的普及,很多应用都基于LBS功能,附近的某某(餐馆.银行.妹纸等等).基础数据中,一般保存了目标位置的经纬度:利用用户提供的经纬度,进行对比,从而获得是否在附近.这里需要在设置出一个字段, ...

  2. hdu 4746 Mophues 莫比乌斯反演+前缀和优化

    Mophues 题意:给出n, m, p,求有多少对a, b满足gcd(a, b)的素因子个数<=p,(其中1<=a<=n, 1<=b<=m) 有Q组数据:(n, m, ...

  3. Sqlmap下载安装与基础命令使用

    本文介绍一下Sqlmap的安装跟配置环境变量. 顺便附上一些常用的命令 SQLMAP-64位.Python 下载链接:http://pan.baidu.com/s/1c0D82fm 密码:d7ec P ...

  4. VS调试错误:“没有可用于当前位置的源代码”的解决方案

    今天,有朋友在问为什么我在调试的时候会出现"没有可用于当前位置的源代码"的错误呢? MSDN上的说法:没有可用于当前位置的源代码,项目不包含您试图查看代码的源代码.原因通常是双击了 ...

  5. py2exe把python程序转换exe

    1.首先下载py2exe:https://sourceforge.net/projects/py2exe/ 2.假设要打包的python 文件放在C:\packet路径下 如 果你有一个名为myscr ...

  6. JavaScript typeof function()的注意事项

    首先,上一段代码: var f = function g() { return 23; }; console.log(typeof g); //输出undefined //console.log(ty ...

  7. PHP漏洞全解(二)-命令注入攻击

    本文主要介绍针对PHP网站常见的攻击方式中的命令攻击.Command Injection,即命令注入攻击,是指这样一种攻击手段,黑客通过把HTML代码输入一个输入机制(例如缺乏有效验证限制的表格域)来 ...

  8. centos 5.x 升级openssl

    今日想在centos 5.2上面安装mysql 5.5.37,在make的时候提示: Linking C shared module adt_null.so [ 65%] Built target a ...

  9. Linux使用wake_up_interruptible()唤醒注册到等待队列上的进程

    http://blog.sina.com.cn/s/blog_4770ef020101h48l.html     功能:唤醒注册到等待队列上的进程 原型:     #include     void ...

  10. SPRING IN ACTION 第4版笔记-第四章ASPECT-ORIENTED SPRING-008-带参数的ADVICE

    一. 假设有情形如:cd里有很多轨,当播放音乐时,要统计每个音轨的播放次数,这些统计操作不应放在播放方法里,因为统计不是播放音乐的主要职责,这种情况适合应用AOP. 二. 1. package sou ...