线程

学习线程相关的笔记,前面写过关于很多线程的使用,有兴趣的可以去了解下

线程

概念理解

  • 并发 : 指两个或多个事件在同一个时间段内发生(交替执行)。
  • 并行 : 指两个或多个事件在同一时刻发生(同时发生)。
  • 进程 : 是指一个内存中运行的应用程序,每个进程都有一个独立的内存空间,一个应用程序可以同时运行多

    个进程;进程也是程序的一次执行过程,是系统运行程序的基本单位;系统运行一个程序即是一个进程从创

    建、运行到消亡的过程。
  • 线程 : 进程内部的一个独立执行单元;一个进程可以同时并发的运行多个线程,可以理解为一个进程便相当

    于一个单 CPU 操作系统,而线程便是这个系统中运行的多个任务(一个程序至少有一个进程,一个进程可以有多个线程)。

线程和进程的区别 :

1.进程:有独立的内存空间,进程中的数据存放空间(堆空间和栈空间)是独立的,至少有一个线程。

2.线程:堆空间是共享的,栈空间是独立的,线程消耗的资源比进程小的多。

多线程的原理

![线程的原理

](https://images2018.cnblogs.com/blog/1224549/201807/1224549-20180717193220192-572225937.jpg)

从图中可以看出,线程的启动实际上是开辟了新的空间,这样的话jvm就可以在U盾讴歌栈之间相互切换,这个就是多线程的原理.

Runnable接口

Runnable是多线程的祖宗类,多线程都间接或直接的实现了这个接口.内部只有run方法,所以也可以看出run方法时多线程的核心.

Thread类

先了解一下Thread类的内部方法:

构造方法:

  • public Thread() :分配一个新的线程对象。
  • public Thread(String name) :分配一个指定名字的新的线程对象。
  • public Thread(Runnable target) :分配一个带有指定目标新的线程对象。
  • public Thread(Runnable target,String name) :分配一个带有指定目标新的线程对象并指定名字。

常用方法:

  • public String getName() :获取当前线程名称。
  • public void start() :导致此线程开始执行; Java虚拟机调用此线程的run方法。
  • public void run() :此线程要执行的任务在此处定义代码。
  • public static void sleep(long millis) :使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行)。
  • public static Thread currentThread() :返回对当前正在执行的线程对象的引用。

使用Thread来创建线程

  1. 创建Thread类的子类
  2. 在Thread类的子类中重写run方法,设置线程任务
  3. 创建Thread类的子类
  4. 调用Thread类的方法start方法,开启新的线程,执行run方法.(这需要注意,是调用start方法,而不是直接调用run方法)

void start() :导致此线程开始执行; Java虚拟机调用此线程的run方法。结果是两个线程并发执行,当前线程(main)

和另一个线程(创建的新线程,执行其run方法),多次启动一个线程是非法的.特别当线程已经结束后,不能重新启动.java程序

是抢占式调度,哪个线程优先级高,哪个线程先执行;同一个优先级,随机选择一个.

获取线程名称

获取线程的名称有两种方法:

  • 使用getName()获取线程名称,这个需要使用Thread类的子类对象来调用.
  • 使用Thread.currentThread().getName()获取线程名称(推荐使用)
设置线程名称

设置线程的名称也有两种方式:

  • 使用setName()方法设置线程名称,也是需要Thread类或者子类的对象调用.
  • 使用构造方法,可以使用有参构造来设置线程名称.

Runnable接口

  1. 定义一个类,实现Runnable接口(任务类).
  2. 重写Runnable的run方法
  3. 创建任务类对象
  4. 创建线程类对象,并将任务对象参数作为参数进行传递
  5. 使用线程类对象调用start方法启动线程.

这个过程中需要注意的是第四步,需要使用public Thread(Runnable target) :分配一个带有指定目标新的线程对象。

public Thread(Runnable target,String name) :分配一个带有指定目标新的线程对象并指定名字。这两个构造方法.

创建线程的方式

  • 实现Runnable接口

      /**
    * 使用实现Runnable接口实现多线程
    *
    * @author WZLOVE
    * @create 2018-07-16 19:46
    */
    public class MyRunnable implements Runnable{ @Override
    public void run() {
    for (int i = 0; i < 100; i++) {
    System.out.println(Thread.currentThread().getName() + ":" + i);
    }
    }
    }
  • 继承Thread类

      /**
    * 使用继承实现多线程
    *
    * @author WZLOVE
    * @create 2018-07-16 19:47
    */
    public class MyThread extends Thread{ public MyThread() {
    } public MyThread(String name) {
    super(name);
    } @Override
    public void run() {
    for (int i = 0; i < 100; i++) {
    System.out.println(getName() + ":" + i);
    }
    }
    }
  • 不同的方法实现多线程,创建对象使用的方式也不同:

      /**
    * @author WZLOVE
    * @create 2018-07-16 19:45
    */
    public class ThreadDemo { public static void main(String[] args) {
    // 继承创建对象相对简单
    MyThread mt = new MyThread("继承");
    mt.start(); // 实现接口创建对象
    // 创建自定义类对象
    MyRunnable mr = new MyRunnable();
    // 创建线程对象
    Thread thread = new Thread(mr,"实现接口");
    thread.start();
    }
    }

注意点:

1.实际上,Thread类也实现了Runnable接口.

2.所有的多线程代码都在run方法里面

3.所有的多线程代码都是通过运行Thread的start()方法来运行的

4.Runnable对象仅仅作为Thread对象的target,Runnable实现类里包含的run()方法仅作为线程执行体。

而实际的线程对象依然是Thread实例,只是该Thread线程负责执行其target的run()方法。

实现Runnable接口与继承Thread类的不同点

使用接口比类是更有优势的:

  • 可以避免java中的单继承的局限性。
  • 增加程序的健壮性,实现解耦操作,代码可以被多个线程共享,代码和线程独立(任务类和线程类进行分离,解耦)。
  • 但是实现接口不能直接使用Thread类的方法,但是可以通过获取当前线程对象进行调用方法.
  • 适合多个相同的程序代码的线程去共享同一个资源。
  • 线程池只能放入实现Runable或Callable类线程,不能直接放入继承Thread的类。

线程的安全问题的产生

线程的安全问题的产生是由于多个线程对共享资源的访问.简单的说线程安全问题都是由全局变量及静态变量引起的。

若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;

若有多个线程同时执行写操作,一般都需要考虑线程同步,否则的话就可能影响线程安全。

买电影票的例子(出现安全问题,运行一下):

package com.wzlove.thread.movie;

/**
* 票数的任务类
*
* @author WZLOVE
* @create 2018-07-17 14:35
*/
public class TicketRunnableImpl implements Runnable{
/**
* 定义共享资源
*/
private int ticket = 100;
@Override
public void run() {
while (true){
if(ticket > 0){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在卖第"+ ticket -- + "张票");
} }
}
} package com.wzlove.thread.movie; /**
* 多线程安全问题的测试
*
* @author WZLOVE
* @create 2018-07-17 14:37
*/
public class MovieDemo { public static void main(String[] args) {
// 创建任务类对象
TicketRunnableImpl ticketRunnable = new TicketRunnableImpl();
// 创建线程对象
Thread t1 = new Thread(ticketRunnable,"窗口1");
Thread t2 = new Thread(ticketRunnable,"窗口2");
Thread t3 = new Thread(ticketRunnable,"窗口3");
// 开始线程
t1.start();
t2.start();
t3.start();
}
}

上面的情况就会出现线程安全问题.

线程的安全问题的解决

使用同步解决线程的安全问题.

  • 同步代码块
  • 同步方法
  • lock锁机制

1.同步代码块

格式 :

    // 同步对象可一是任意对象,推荐使用this
synchronized(同步对象){
可能出现同步问题的代码
}

锁对象可以是任意对象,但是锁对象必须唯一.

2.同步方法

格式:

    // 同步方法也是有锁对象的,也就是当前对象this
修饰符 synchronized 返回值类型 方法名(参数列表){
可能出现同步问题的代码
}

需要注意的是静态同步方法内的同步锁不是this(因为静态代码的执行在this之前产生),而是类的字节码对象,也就是(类名.class)

3.Lock锁机制

  • public void lock() :加同步锁。
  • public void unlock() :释放同步锁。

使用步骤:

  1. 创建ReentrantLock的对象
  2. 在使用共享资源前使用lock方法进行加锁
  3. 在使用共享资源结束后使用unlock方法释放同步锁

线程状态的概述

线程状态 导致状态发生条件
new()新建 线程刚被创建,但是并未启动。还没调用start方法。
Runnable(可运行) 线程可以在java虚拟机中运行的状态,可能正在运行自己代码,也可能没有,这取决于操
作系统处理器。
Blocked(锁阻塞) 当一个线程试图获取一个对象锁,而该对象锁被其他的线程持有,则该线程进入Blocked状
态;当该线程持有锁时,该线程将变成Runnable状态。
Waiting(无限等待) 一个线程在等待另一个线程执行一个(唤醒)动作时,该线程进入Waiting状态。进入这个
状态后是不能自动唤醒的,必须等待另一个线程调用notify或者notifyAll方法才能够唤醒。
Timed Waiting(计时等待) 同waiting状态,有几个方法有超时参数,调用他们将进入Timed Waiting状态。这一状态
将一直保持到超时期满或者接收到唤醒通知。带有超时参数的常用方法有Thread.sleep 、
Object.wait。
Teminated(被终止) 因为run方法正常退出而死亡,或者因为没有捕获的异常终止了run方法而死亡。

状态图:

等待唤醒机制

Object类中的四个方法:

  • wait() : 使线程处于等待状态,等待着其他的线程唤醒
  • wait(long millis) : 使线程处于等待状态, 等待着其他的线程唤醒/等待时间到达
  • notify() : 唤醒其他的单个等待的线程
  • notifyAll() : 唤醒其他的所有等待的线程

sleep()与wait()

  • sleep:Thread类中的静态方法,休眠指定的时间,在指定时间后自动唤醒,不回释放锁对象
  • wait : Object类中的方法,无限等待,等待其他线程的唤醒,必须释放锁对象

java之初学线程的更多相关文章

  1. 小谈Java里的线程

    今天,我们来谈一谈Java里的线程. 一.进程与线程的基本概念 大家可能没听过线程这个概念,但是相信,用计算机的朋友都听过进程这个概念.打开电脑的任务管理器,我们就可以看到许多进程.它们主要分为三类, ...

  2. Java 四种线程池newCachedThreadPool,newFixedThreadPool,newScheduledThreadPool,newSingleThreadExecutor

    介绍new Thread的弊端及Java四种线程池的使用,对Android同样适用.本文是基础篇,后面会分享下线程池一些高级功能. 1.new Thread的弊端执行一个异步任务你还只是如下new T ...

  3. 【转】关于Java的Daemon线程的理解

    原文地址:http://www.cnblogs.com/ChrisWang/archive/2009/11/28/1612815.html 关于Java的Daemon线程的理解 网上对Java的Dae ...

  4. Java四种线程池

    Java四种线程池newCachedThreadPool,newFixedThreadPool,newScheduledThreadPool,newSingleThreadExecutor 时间:20 ...

  5. java笔记--使用线程池优化多线程编程

    使用线程池优化多线程编程 认识线程池 在Java中,所有的对象都是需要通过new操作符来创建的,如果创建大量短生命周期的对象,将会使得整个程序的性能非常的低下.这种时候就需要用到了池的技术,比如数据库 ...

  6. Java中的线程

    http://hi.baidu.com/ochzqvztdbabcir/item/ab9758f9cfab6a5ac9f337d4 相濡以沫 Java语法总结 - 线程 一 提到线程好像是件很麻烦很复 ...

  7. [译]线程生命周期-理解Java中的线程状态

    线程生命周期-理解Java中的线程状态 在多线程编程环境下,理解线程生命周期和线程状态非常重要. 在上一篇教程中,我们已经学习了如何创建java线程:实现Runnable接口或者成为Thread的子类 ...

  8. Java多线程和线程池

    转自:http://blog.csdn.net/u013142781/article/details/51387749 1.为什么要使用线程池 在Java中,如果每个请求到达就创建一个新线程,开销是相 ...

  9. Java并发编程:线程和进程的创建(转)

    Java并发编程:如何创建线程? 在前面一篇文章中已经讲述了在进程和线程的由来,今天就来讲一下在Java中如何创建线程,让线程去执行一个子任务.下面先讲述一下Java中的应用程序和进程相关的概念知识, ...

随机推荐

  1. Robot的使用

    在Java中,有一个类,非常神奇,它能帮助你完成某些任务,例如:打开笔记本/QQ等. 今天,我就说一下Robot类的使用方法吧,做一个打开记事本的小程序. 1.准备工作 JDK:不知道的别看了 开发工 ...

  2. Java中的==符号与equals()的使用(测试两个变量是否相等)

    Java 程序中测试两个变量是否相等有两种方式:一种是利用 == 运算符,另一种是利用equals()方法. 当使用 == 来判断两个变量是否相等时,如果两个变量是基本类型变量,且都是数值类型(不一定 ...

  3. Erlang运行时中的无锁队列及其在异步线程中的应用

    本文首先介绍 Erlang 运行时中需要使用无锁队列的场合,然后介绍无锁队列的基本原理及会遇到的问题,接下来介绍 Erlang 运行时中如何通过“线程进度”机制解决无锁队列的问题,并介绍 Erlang ...

  4. D.王者荣耀交流协会——PSP Daily(测评人:贾男男)

    D.王者荣耀交流协会——PSP Daily(测评人:贾男男) 一.基于NABCD评论作品,及改进建议 每个小组评论其他小组beta发布的作品.1.根据(不限于)NABCD评论作品的选题;2.评论作品对 ...

  5. JSON toBean Timestamp To Date 时间戳转日期

    时间戳格式的时间从json转为date时 配置: import java.util.Date; import net.sf.ezmorph.object.AbstractObjectMorpher; ...

  6. 2018-2019-20172329 《Java软件结构与数据结构》第七周学习总结

    2018-2019-20172329 <Java软件结构与数据结构>第七周学习总结 教材学习内容总结 <Java软件结构与数据结构>第十一章-二叉查找树 一.概述 1.什么是二 ...

  7. 06慕课网《进击Node.js基础(一)》作用域和上下文

    作用域 function(){}大括号中的内容是一个作用域; function 和 var 的声明会被提到作用域的最上面 function f(){ a = 2; var b = g(); //此处可 ...

  8. java(系统)实战1

    在简单学习了java的布局和一些界面的绘制方法后,我便开始有了跟着视频和书本的知识学做一个简单的餐饮系统,才能激发自己的编程和不断巩固知识. 我简单说明一下本次做的系统很普通但具有实用性,是通过jav ...

  9. spring冲刺计划

    会议召开时间表 日期 时间 内容 05/09 21:00-22:00 讨论题目(未果) 05/10 21:00-21:30 确定题目(网络助手) 05/13 21:00-21:45 讨论软件页面设计 ...

  10. Beat(2/7)

    目录 摘要 团队部分 个人部分 摘要 队名:小白吃 组长博客:hjj 作业博客:beta冲刺(2/7) 团队部分 后敬甲(组长) 过去两天完成了哪些任务 整理博客 做了点商家数据表格 接下来的计划 做 ...