概述

进程:

是一个正在执行中的程序

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

线程:

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

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

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

创建线程

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

  1. 1: class Sell extends Thread

  1. 2: {

  1. 3: private int tickets = 100;

  1. 4: Sell()

  1. 5: {

  1. 6: //启动线程

  1. 7: start();

  1. 8: }

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

  1. 10: public void run()

  1. 11: {

  1. 12: while(tickets > 0)

  1. 13: {

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

  1. 15: }

  1. 16: }

  1. 17: }

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

  1. 1: class Sell implements Runnable

  1. 2: {

  1. 3: private int tickets = 100;

  1. 4:

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

  1. 6: public void run()

  1. 7: {

  1. 8: while(tickets > 0)

  1. 9: {

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

  1. 11: }

  1. 12: }

  1. 13: }

  1. 14: class ThreadDemo

  1. 15: {

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

  1. 17: {

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

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

  1. 20: }

  1. 21: }

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

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

线程权限问题

线程安全问题--同步

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

  1. 1: 

  1. 2: class Sell implements Runnable

  1. 3: {

  1. 4: private int tickets = 10;

  1. 5:

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

  1. 7: public void run()

  1. 8: {

  1. 9: while(tickets > 0)

  1. 10: {

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

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

  1. 13: }

  1. 14: }

  1. 15: }

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

解决方法

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

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

synchronized(对象)

{

需要被同步的代码

}

synchronized void show()

{

函数内容

}

  1. 1: class Sell implements Runnable

  1. 2: {

  1. 3: private int tickets = 10;

  1. 4:

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

  1. 6: public void run()

  1. 7: {

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

  1. 9: synchronized(this)

  1. 10: {

  1. 11: while(tickets > 0)

  1. 12: {

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

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

  1. 15: }

  1. 16: }

  1. 17: }

  1. 18: }

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

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

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

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

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

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

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

  1. 1: class Tickets

  1. 2: {

  1. 3: static int tickets = 10;

  1. 4: public static void sell()

  1. 5: {

  1. 6: //类对象作为锁

  1. 7: synchronized(Selling.class)

  1. 8: {

  1. 9: if(tickets > 0)

  1. 10: {

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

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

  1. 13: }

  1. 14: }

  1. 15: }

  1. 16: }

  1. 17: 

  1. 18: class Selling implements Runnable

  1. 19: {

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

  1. 21: public void run()

  1. 22: {

  1. 23: while(Tickets.tickets> 0)

  1. 24: {

  1. 25: Tickets.sell();

  1. 26: }

  1. 27: }

  1. 28: }

同步的前提:

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

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

同步的利弊

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

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

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

如何编写多线程

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

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

死锁

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

  1. 1: 

  1. 2: class A implements Runnable

  1. 3: {

  1. 4: String a = "a";

  1. 5: 

  1. 6: public void run()

  1. 7: {

  1. 8: while(true)

  1. 9: {

  1. 10: //A抢占A锁

  1. 11: synchronized(A.class)

  1. 12: {

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

  1. 14: //A抢占B锁

  1. 15: synchronized(B.class)

  1. 16: {

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

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

  1. 19: }

  1. 20: }

  1. 21: }

  1. 22: }

  1. 23: }

  1. 24: 

  1. 25: class B implements Runnable

  1. 26: {

  1. 27: String b = "b";

  1. 28: 

  1. 29: public void run()

  1. 30: {

  1. 31: while(true)

  1. 32: {

  1. 33: //B抢占B锁

  1. 34: synchronized(B.class)

  1. 35: {

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

  1. 37: //B抢占A锁

  1. 38: synchronized(A.class)

  1. 39: {

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

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

  1. 42: }

  1. 43: }

  1. 44: }

  1. 45: }

  1. 46: }

  1. 47: class DeadlockDemo

  1. 48: {

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

  1. 50: {

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

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

  1. 53: }

  1. 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. sublime主题推荐

    PS:之前在CSDN上写的文章,现在转到博客园~ 寒假的时候发现一个sublime主题,我觉得很赞哦~~推荐给大家~~ 下载方式 step1:ctrl+shift+p  调出command palet ...

  2. android实现视频图片取缩略图

    取缩略图不等同于缩放图片. 缩放图片是保持不失真的情况下缩放处理,并进行平滑处理. 缩略图则不然,允许失真,目的只是取出图片的轮廓. 保存Bitmap图片 private void saveBitma ...

  3. TIBCO ActiveMatrix BPM 生成daa包脚本

    Ant 配置: <?xml version="1.0" encoding="UTF-8" ?> <project name="pro ...

  4. 用最直白的语言告诉你,hadoop是什么?

    hadoop应历史之潮流,随着理论探索.科学技术试验的不断开展,hadoop终于2006年问世,惊天地泣鬼神! hadoop雏形开始于2002年的Apache的Nutch,Nutch是一个开源Java ...

  5. Razor语法小记

    1.代码块中,<text>标签用来输出,如: @{ <text>sdfsdf</text> } 输出Html: sdfsdf

  6. ASP.NET MVC 3 Razor Views in SharePoint

    http://tqcblog.com/2011/01/22/asp-net-mvc-3-razor-views-in-sharepoint/ ASP.NET MVC 3 has just been r ...

  7. 数据结构---顺序表(C++)

    顺序表 是用一段地址连续的存储单元依次存储线性表的数据元素. 通常用一维数组来实现 基本操作: 初始化 销毁 求长 按位查找 按值查找 插入元素 删除位置i的元素 判空操作 遍历操作 示例代码: // ...

  8. CSS文档流与块级元素和内联元素(文档)

    CSS文档流与块级元素(block).内联元素(inline),之前翻阅不少书籍,看过不 少文章, 看到所多的是零碎的CSS布局基本知识,比较表面.看过O'Reilly的<CSS权威指 南> ...

  9. linux dump 命令详解

    功能说明:备份文件系统. 语 法:dump [-cnu][-0123456789][-b <区块大小>][-B <区块数目>][-d <密度>][-f <设备 ...

  10. 如何启动 SQL Server Agent(SQL Server 配置管理器)

    如何启动 SQL Server Agent(SQL Server 配置管理器) SQL Server 2008 R2 其他版本   4(共 6)对本文的评价是有帮助 - 评价此主题 可以从 SQL S ...