进程与线程

首先来看百度百科关于进程的介绍:

进程是一个具有独立功能的程序关于某个数据集合的一次运行活动。它可以申请和拥有系统资源,是一个动态的概念,是一个活动的实体。它不只是程序的代码,还包括当前的活动,通过程序计数器的值和处理寄存器的内容来表示。

直观一点:

windows的任务管理里面,我们看到的eclipse和360等等,都是进程。(想深入了解的可以看看计算机操作系统)

什么是线程?

线程是在一个进程独立运行的子任务。线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。

打个比如说,我们都用的QQ软件,它是一个进程,我们可以和人一边聊天一边传输文件,这就是多线程。

为什么要使用多线程?

1.多线程可以充分的利用系统的cpu,达到更快的处理效果

2.提高系统的运行效率

想入更深入了解的可以重新学习计算机操作系统,这里就不多介绍了,接下来我们怎么用!(毕竟这才是关键)

Thread and Runnable

Java中实现线程有两个方式,一个是继承Thread,另一个是实现Runnable接口,首先来看继承Thread的第一个实例:

  1. package com.chapter1;
  2.  
  3. public class FirstThread {
  4.  
  5. public static void main(String[] args) {
  6. InnerThread thread = new InnerThread();
  7. // 线程启动
  8. thread.start();
  9. }
  10.  
  11. }
  12.  
  13. class InnerThread extends Thread {
  14.  
  15. // Override run方法,写入自己想要实现的业务
  16. @Override
  17. public void run() {
  18. super.run();
  19. System.out.println("Hello World!");
  20. }
  21. }

继承run方法的时候,我们通常会重写run方法,来实现自己的业务,接下来看,如何使用Runnable实现线程:

  1. package com.chapter1;
  2.  
  3. public class FirstRunnable {
  4.  
  5. public static void main(String[] args) {
  6. MyRunnable myRunnable;
  7. myRunnable = new MyRunnable();
  8. new Thread(myRunnable).start();
  9. }
  10.  
  11. }
  12.  
  13. class MyRunnable implements Runnable {
  14.  
  15. @Override
  16. public void run() {
  17. System.out.println("Hello World!");
  18. }
  19. }

Runnable是一个接口,接口意味着更加灵活一些,也是推荐使用实现Runable接口来写线程的。

现在我们看到的都是一个单线程的例子,接下来写一个多线程的:

  1. package com.chapter1;
  2. /**
  3. * 多个线程实例
  4. * @author tangj
  5. *
  6. */
  7. public class ManyThread {
  8.  
  9. public static void main(String args[]) {
  10. Runnable runnable = new MyRunnable2();
  11. new Thread(runnable, "a").start();
  12. new Thread(runnable, "b").start();
  13. new Thread(runnable, "c").start();
  14. new Thread(runnable, "d").start();
  15. }
  16. }
  17.  
  18. class MyRunnable2 implements Runnable {
  19.  
  20. int count = 0;
  21. @Override
  22. public void run() {
  23. autoIncrement();
  24. System.out.println(Thread.currentThread().getName()+"计算了"+"count:" + count);
  25. }
  26. // 执行自增操作
  27. private void autoIncrement(){
  28. count++;
  29. }
  30. }

我们来看下运行结果:

再运行一次

可以看到,多线程的执行是无序的,而且这个结果有点奇怪,难道不是从1增加到4吗,怎么会出现重复的?

在JVM中,执行自增操作的分为三个步骤:

1.取得现有值count

2.执行count+1操作

3.将count+1赋值给count.

所以就会遇到这样的情况,一个线程在取得count值的时候,count操作正处于第二个步骤,上一个线程执行的还未进行赋值操作,这就涉及到线程安全问题。

下面给出上一个例子的解决方案

  1. package com.chapter1;
  2.  
  3. /**
  4. * 多个线程实例
  5. *
  6. * @author tangj
  7. *
  8. */
  9. public class ManyThread {
  10.  
  11. public static void main(String args[]) {
  12. Runnable runnable = new MyRunnable2();
  13. new Thread(runnable, "a").start();
  14. new Thread(runnable, "b").start();
  15. new Thread(runnable, "c").start();
  16. new Thread(runnable, "d").start();
  17. }
  18. }
  19.  
  20. class MyRunnable2 implements Runnable {
  21.  
  22. int count = 0;
  23.  
  24. // 注意在这里增加了关键字 synchronized
  25. @Override
  26. synchronized public void run() {
  27. autoIncrement();
  28. System.out.println(Thread.currentThread().getName() + "计算了" + "count:" + count);
  29. }
  30.  
  31. // 执行自增操作
  32. private void autoIncrement() {
  33. count++;
  34. }
  35. }

来看输出结果(多执行几次):

我们可以看到:不管哪个线程先执行,最后的打印顺序肯定是递增的顺序。

接下来我们看另外一中实现方式:使用重入锁(ReentrantLock)

  1. package com.chapter1;
  2.  
  3. import java.util.concurrent.locks.Lock;
  4. import java.util.concurrent.locks.ReentrantLock;
  5.  
  6. public class ManyThread2 {
  7.  
  8. public static void main(String[] args) {
  9. Runnable runnable = new MyRunnable3();
  10. new Thread(runnable, "a").start();
  11. new Thread(runnable, "b").start();
  12. new Thread(runnable, "c").start();
  13. new Thread(runnable, "d").start();
  14. }
  15. }
  16.  
  17. class MyRunnable3 implements Runnable{
  18.  
  19. int count = 0;
  20. // 使用重入锁ReentrantLock
  21. Lock lock = new ReentrantLock();
  22.  
  23. @Override
  24. public void run() {
  25. // 锁住
  26. lock.lock();
  27. count++;
  28. System.out.println(Thread.currentThread().getName() + "计算了" + "count:" + count);
  29. // 解锁
  30. lock.unlock();
  31. }
  32.  
  33. }

得到的结果也是整齐的递增顺序,说明它也是线程安全的。

总结

所以以后开发多线程的业务的时候,首先应该考虑的问题应该是这样的一个流程:

1.能否用单线程解决?(单线程本身就是线程安全的)

2.我开发的多线程业务是否线程安全?

线程安全是保证程序正常运行的关键,所以应该把线程安全作为开发多线程对于考虑的首要问题

最后说两句:

本文所以代码都更新到我的github中,大家可以去clone或者Fork,我会持续更新的。

点击这里进入我的Github
喜欢的朋友可以点击下方的推荐,或者写个评论我们共同探讨Java高并发!!!

Java多线程高并发学习笔记(一)——Thread&Runnable的更多相关文章

  1. Java多线程高并发学习笔记——阻塞队列

    在探讨可重入锁之后,接下来学习阻塞队列,这边篇文章也是断断续续的写了很久,因为最近开始学ssm框架,准备做一个自己的小网站,后续可能更新自己写网站的技术分享. 请尊重作者劳动成果,转载请标明原文链接: ...

  2. Java多线程高并发学习笔记(二)——深入理解ReentrantLock与Condition

    锁的概念 从jdk发行1.5版本之后,在原来synchronize的基础上,增加了重入锁ReentrantLock. 本文就不介绍synchronize了,有兴趣的同学可以去了解一下,本文重点介绍Re ...

  3. JAVA多线程高并发学习笔记(三)——Callable、Future和FutureTask

    为什么要是用Callable和Future Runnable的局限性 Executor采用Runnable作为基本的表达形式,虽然Runnable的run方法能够写入日志,写入文件,写入数据库等操作, ...

  4. Java多线程高并发学习笔记(三)——深入理解线程池

    线程池最核心的一个类:ThreadPoolExecutor. 看一下该类的构造器: public ThreadPoolExecutor(int paramInt1, int paramInt2, lo ...

  5. Java 多线程高并发编程 笔记(一)

    本篇文章主要是总结Java多线程/高并发编程的知识点,由浅入深,仅作自己的学习笔记,部分侵删. 一 . 基础知识点 1. 进程于线程的概念 2.线程创建的两种方式 注:public void run( ...

  6. JAVA 多线程和并发学习笔记(三)

    Java并发编程中使用Executors类创建和管理线程的用法 1.类 Executors Executors类可以看做一个“工具类”.援引JDK1.6 API中的介绍: 此包中所定义的 Execut ...

  7. Java 多线程高并发编程 笔记(二)

    1. 单例模式(在内存之中永远只有一个对象) 1.1 多线程安全单例模式——不使用同步锁 public class Singleton { private static Singleton sin=n ...

  8. JAVA 多线程和并发学习笔记(二)

    一.Java中创建线程方法 1. 继承Thread类创建线程类 定义Thread类的子类,重写该类的run()方法.该方法为线程执行体. 创建Thread子类的实例.即线程对象. 调用线程对象的sta ...

  9. JAVA 多线程和并发学习笔记(四)

    1. 多进程 实现并发最直接的方式是在操作系统级别使用进程,进程是运行在它自己的地址空间内的自包容的程序.多任务操作系统可以通过周期性地将CPU从一个进程切换到另一个进程,来实现同时运行多个进程. 尽 ...

随机推荐

  1. java核心技术卷一笔记(1)

    jdk是java开发工具包,里面包含了javac.jar.javadoc.java等工具,可以在bin目录中找到.有一个文件夹是jre,即jdk也包含了java运行环境.jre可单独安装,只是运行ja ...

  2. Fedora25和win10双系统安装及使问题汇总

    安装问题汇总 1.U盘引导制作后,开机出现":Assuming driver cache: write through" 解决方案:经过排查后,怀疑是U盘启动制作出了问题,后来查阅 ...

  3. IT类非开发面试总结--1

    面试总结.. ================================= 第一部分.. -------------2. 电脑开机时风扇转, 但是屏幕没有任何显示, 此现象可能是哪些方面所导致? ...

  4. 用notepad如何在每行结尾处添加特殊字符

    在处理关键词的时候,有时候需要将每一行的末尾添加某个特殊字符,较常用的一种方法就是用excel拼接起来.今天要分享是一种简单的方法,用notepad就可以很容易实现,主要用到notepad中的扩展匹配 ...

  5. HTTP服务器

    1.项目介绍 HTTP协议是应用层的面向对象的协议,由于其简捷.快速的方式,适用于分布式超媒体信息系统.协议的详细内容,前面一篇HTTP协议详解已经详细介绍了,这里不再赘述. 项目总体描述:HTTP支 ...

  6. 【前端】vue.js环境配置以及实例运行简明教程

    vue.js环境配置以及实例运行简明教程 声明:本文档编写参考如下两篇博客,是对它们的修改与补充,欢迎点击链接查看原文: 原文1:vue.js在windows本地下搭建环境和创建项目 原文2:Vue. ...

  7. [2015-11-10]分享一个调用msbuild生成解决方案并打包发布的批处理脚本

    最近工作成果之一,特此记录. 用于打包的批处理脚本 注意设置 path/to/your/solutionfile.sln 指向vs的解决方案文件. setlocal enabledelayedexpa ...

  8. Ibatis insert语句插入null引发的错误

    公司使用的orm框架为ibatis,其中默认的insert语句一直都是这样写的: <insert id="insert" parameterClass="activ ...

  9. Microsoft .Net Remoting系列专题之一:.Net Remoting基础篇

    Microsoft .Net Remoting系列专题之一 一.Remoting基础 什么是Remoting,简而言之,我们可以将其看作是一种分布式处理方式.从微软的产品角度来看,可以说Remotin ...

  10. cocoapods的安装和使用以及版本升级遇到的问题

    一.CocoaPods是什么? CocoaPods是一个负责管理iOS项目中第三方开源库的工具.CocoaPods的项目源码在Github上管理.该项目开始于2011年8月12日,在这两年多的时间里, ...