一、线程的初步认识

在上周去面试的时候,面试官问了我一个关于线程池的问题,当时没有答上来。所以,回来了之后决定重新学习一下多线程。
      这也是本人第一次写博客,之前一直想写,但是,一直没有搞清楚博客园的博客系统是怎么玩的。这次,到网上看到了一些关于博客园的小技巧,正好最近在学习多线程,拿来练练手。

1.创建线程

 1 public class Demo {
 2     public static void main(String [] args){
 3         //方法一:通过继承Thread类,当调用start()方法时,就会启动一个线程去执行run方法里面的代码。这里直接使用内部类。
 4         new Thread(){
 5             public void run() {
 6                 System.out.println(Thread.currentThread().getName());
 7             };
 8         }.start();
 9
10         //方法二:实现Runnable接口
11         Runnable r = new Runnable() {
12             @Override
13             public void run() {
14                 System.out.println(Thread.currentThread().getName());
15             }
16         };
17         new Thread(r).start();
18
19         /**
20          * 不管用哪种方法调用线程的启动都是调用Thread类的start()方法。
21          * 只是执行任务由可以是Thread中run方法,也可以是Runnable接口的run方法。
22          */
23     }
24 }

2.线程安全

 1 public class Demo2 {
 2     private int value = 1;
 3
 4     public int getNext(){
 5         return value++;
 6     }
 7
 8     public static void main(String[] args) {
 9         final Demo2 demo = new Demo2();
10         Runnable r = new Runnable() {
11             @Override
12             public void run() {
13                 System.out.println(demo.getNext());
14             }
15         };
16         /**
17          * 当少量线程同时访问getNext()方法时,程序不会有什么问题。
18          * 但是如果并发量较大(这里模拟500个线程同时访问),得到结果往往不是想要的结果。
19          */
20         for(int i = 0 ;i <500;i++){
21             new Thread(r).start();
22         }
23     }
24
25 }

出现问题的原因是:value++不是一个原子操作,或者说该操作不具备原子性。
原子性:原子是世界上最小的单位,具有不可分割性。在我们编程的世界里,某个操作如果不可分割我们就称之为该操作具有原子性。i=0不可能再分割,所以该操作具有原子性。但是getNext()方法的value++,是可以分割的,这实际上有个“读取-修改-写入”的操作序列。如果一个操作具有原子性,那也就不会有线程安全问题。做完了就做完了!但是一个操作不具有原子性,那么,在这个操作在执行的过程中,有可能被外部所改变。

解析:这个类有一个字段value,并且提供了可改变字段的方法,所以该对象的状态是可变的。上面程序多个线程同时访问getNext()方法时。如果线程是按顺序执行,正确的执行方式是第一条线程读取value的值并打印出来,然后对齐值进行自增操作。然后下一条线程再读取value值,接着打印、自增...,结果值应该是 1、2、3、4、5...500  按顺序打印出来,我们希望的结果也是这样。但是,多线程之间的操作是交替执行的,当第一个线程读取value值时,第二个线程也有可能在做读取value值的操作,第三个也可能做着同样的操作。这样,各个线程之间得到的值就有可能相同,而不是理想中按照顺序对value的值进行递增。

解决办法:在run方法上加synchronized(当然也可以在getNext方法上加,只是锁对象不一样而已)

 1 public class Demo2 {
 2     private int value = 1;
 3
 4     public int getNext(){
 5         return value++;
 6     }
 7
 8     public static void main(String[] args) {
 9         final Demo2 demo = new Demo2();
10         Runnable r = new Runnable() {
11             @Override
12             public synchronized void run() {
13                 System.out.println(demo.getNext());
14             }
15         };
16         /**
17          * 当少量线程同时访问getNext()方法时,程序不会有什么问题。
18          * 但是如果并发量较大(这里模拟500个线程同时访问),得到结果往往不是想要的结果。
19          */
20         for(int i = 0 ;i <500;i++){
21             new Thread(r).start();
22         }
23     }
24
25 }
时间: 2024-10-06 11:47:33

一、线程的初步认识的相关文章

python之路 IO多路复用 线程进程初步了解

一.IO多路复用 1.客户端 #!/usr/bin/env python #-*-coding:utf-8-*- import socket sk=socket.socket() sk.connect(('127.0.0.1',8888,)) data=sk.recv(1024) print(data) while True: inp=input('>>>') sk.sendall(bytes(inp,encoding='utf-8')) print(sk.recv(1024)) sk.

Java并发编程——线程池初步

概述: 线程池机制是事先创建一些线程等待服务端程序的调用,这些线程保存在一个数组结构中,称为"线程池".当服务器有任务执行时,就从线程池中取出一个线程并给其分配任务,当线程任务执行完成后,再被放回线程池中. 优点: 1. 由于在任务到达之前,线程已经存在,所以这里为系统消除了线程创建的资源和时间的开销.可以立即为请求服务,使程序响应更快. 2. 通过适当地调节线程池中的线程数目,就强制使一些新到的任务处于等待状态,可以防止资源不足. 参考: http://www.cnblogs.com

进程池和线程的初步

1.进程池 2. 线程      # 理论    # Threading.Thread来创建线程 1.进程池 为什么要有进程池?进程池的概念. 在程序实际处理问题过程中,忙时会有成千上万的任务需要被执行,闲时可能只有零星任务.那么在成千上万个任务需要被执行的时候,我们就需要去创建成千上万个进程么?首先,创建进程需要消耗时间,销毁进程也需要消耗时间.第二即便开启了成千上万的进程,操作系统也不能让他们同时执行,这样反而会影响程序的效率.因此我们不能无限制的根据任务开启或者结束进程.那么我们要怎么做呢

python爬虫番外篇(一)进程,线程的初步了解

原文地址https://www.cnblogs.com/zhaof/p/6994991.html 整理这番外篇的原因是希望能够让爬虫的朋友更加理解这块内容,因为爬虫爬取数据可能很简单,但是如何高效持久的爬,利用进程,线程,以及异步IO,其实很多人和我一样,故整理此系列番外篇 一.进程 程序并不能单独和运行只有将程序装载到内存中,系统为他分配资源才能运行,而这种执行的程序就称之为进程.程序和进程的区别在于:程序是指令的集合,它是进程的静态描述文本:进程是程序的一次执行活动,属于动态概念. 例如我们

一夜搞懂 | JVM 线程安全与锁优化

前言 本文已经收录到我的 Github 个人博客,欢迎大佬们光临寒舍: 我的 GIthub 博客 学习导图 一.为什么要学习内存模型与线程? 之前我们学习了内存模型和线程,了解了 JMM 和线程,初步探究了 JVM 怎么实现并发,而本篇文章,我们的关注点是 JVM 如何实现高效 并发编程的目的是为了让程序运行得更快,提高程序的响应速度,虽然我们希望通过多线程执行任务让程序运行得更快,但是同时也会面临非常多的挑战,比如像线程安全问题.线程上下文切换的问题.硬件和软件资源限制等问题,这些都是并发编程

三、atomic

在java.util.concurrent.atomic提供了一下关于原子操作的类,这些类包括:AtomicLong.AtomicInteger.AtomicBoolean.以及对数组操作的AtomicIntegerArray.AtomicLongArray. 在线程的初步认识的Demo2,因为原子操作导致的安全问题.使用AtomicInteger就可以得到解决. public class Demo2 { private AtomicInteger value = new AtomicInteg

Java并发编程专题

为了防止无良网站的爬虫抓取文章,特此标识,转载请注明文章出处.LaplaceDemon/ShiJiaqi. http://www.cnblogs.com/shijiaqi1066/p/4852149.html 明确并发编程中的一些基本概念 Java 并发(1)多线程基础 Java并发(2)线程安全与线程间通信 Java并发(3)同步容器与并发容器 Java并发(4) Executor框架 —— 线程池初步 Java并发(5)Executor框架 —— 线程池进阶 Java并发(6)带返回结果的任

【Java并发系列01】Thread及ThreadGroup杂谈

img { border: solid black 1px } 一.前言 最近开始学习Java并发编程,把学习过程记录下.估计不是那么系统,主要应该是Java API的介绍(不涉及最基础的概念介绍),想要深入系统学习推荐看一本书<Java Concurrency in Practice >(建议看英文,也可以看中文译本:< Java 并发编程实战>). 并发编程的基础就是线程,所以这一篇对线程做初步了解. 二.Thread和ThredGroup的关系 因为Thread的构造函数中有

处理模型

看完“实现模型”,你是否长吁一声,准备拿起咖啡,惬意的喝上一杯?毕竟我们已经完成了从用例到编码的全过程了,确实是值得庆祝的一件事情,但“革命尚未成功.同志还需努力”,现在还不是享受的时候,接下来我们需要进入“处理模型”阶段. l         “处理模型”阶段的任务 “处理模型”英文是“Process Model”,Process在IT里面又叫“进程”,虽然和进程相关,但直接叫“进程模型”会误导大家,所以我叫它“处理模型”,也就是和处理相关的设计.我们来看看“处理模型”阶段的任务: 1)进程.