《 Java并发编程从入门到精通》Thread安全与不安全

作者:张振华    购买链接:天猫商城  JD商城  当当书店

鸟欲高飞先振翅,人求上进先读书。本文是原书的第3章  Thread安全3.2 什么是不线程安全。3.3什么是线程不安全。

3.2 什么是不安全?

当多个线程同时操作一个数据结构的时候产生了相互修改和串行的情况,没有保证数据的一致性,我们通常称之这种设计的代码为”线程不安全的“。

有这么一个场景,假设5个用户,都来给一个数字加1的工作,那么最后应该是得到加5的结果;看一下下面的事例;

单个用户干活类:Count ;

public class Count {

public int num = 0;

public void add() {

try {

Thread. sleep(5l);//模仿用户干活

catch (InterruptedException e) {

}

num += 1;

System. out.println(Thread.currentThread().getName() + “-” + num);

}

}

用户类,干Count 的活;

package demo.thread;

public class ThreadA extends Thread {

private Count count ;

public ThreadA(Count count) {

this.count =count;

}

public void run() {

count.add();

}

}

5个人干完活:最后的值;

package demo.thread;

public class ThreadMain {

public static void main(String[] args) {

Count count = new Count();

for(int i=0;i<5;i++) {

ThreadA task = new ThreadA(count);

task.start();

}

try {

Thread. sleep(100l);//等5个人干完活

catch (InterruptedException e) {

e.printStackTrace();

}

System. out.println(“5个人干完活:最后的值4″ +count .num );

}

}

运行结果如下:(由于多线程,有不安全问题,其实每次运行下面的结果都是不一样的)

Thread-1-1

Thread-0-1

Thread-3-3

Thread-4-2

Thread-2-3

5个人干完活:最后的值:3

可见不是咱们想要的结果,这就是典型的线程不安全问题;而我们实际工作中,特别是web项目Service和servlet一般都是单例共享变量的就会及其容易出现,多个用户之间的数据串掉了,从而导致最终数据库里面所需要统计的数据不对;

3.3 什么是安全?

我们还看上面的例子只对单个用户干活类:Count ;做如下修改 添加synchronized 关键字;

package demo.thread;

public class Count {

public int num = 0;

public synchronized void add() {

try {

Thread. sleep(5l);//模仿用户干活

catch (InterruptedException e) {

}

num += 1;

System. out.println(Thread.currentThread().getName() + “-” + num);

}

}

运行结果如下:

Thread-0-1

Thread-4-2

Thread-3-3

Thread-2-4

Thread-1-5

5个人干完活:最后的值5

而这次,每次干活都是一样的结果,这就叫线程安全,就是不管多少个用户过来,都保证咱们的数据的高度一致性和准确性就叫线程安全的;这里我们引用了synchronized 的同步锁的机制,这个后面会讲到,来保证了我们的线程安全性;

什么是线程安全性呢?是不是一定要加锁才是线程安全性的呢?个人感觉只要你代码里面没有变量互串,线程之间互不影响,例如server的设计方法,就是线程安全的,例如上面五个人干了同一件事情,如果让5个人干5件不一样的事情,或者1个人干5件事情,那也是安全的。而不安全在java工作中主要针对单例模式的应用而言的,怎么保证一件事情被一群人干完,又快又正确;

想实现线程安全大概有三种方法:

1:多实例,也就是不用单例模式了。

2:使用java.util.concurrent下面的类库。

3:使用锁机制synchronized,lock方式。 

时间: 2025-01-21 03:00:26

《 Java并发编程从入门到精通》Thread安全与不安全的相关文章

《 Java并发编程从入门到精通》 Java线程池的监控

本文是< Java并发编程从入门到精通>第9章 线程的监控及其日常工作中如何分析的9.1节 Java线程池的监控.   看不到不等于不存在!让我们来看看工作中是如何找问题解决问题的. 鸟欲高飞先振翅,人求上进先读书. 京东,亚马逊,当当均有销售. 9.1 Java线程池的监控 如果想实现线程池的监控,必须要自定义线程池继承ThreadPoolExecutor类,并且实现beforeExecute,afterExecute和terminated方法,我们可以在任务执行前,执行后和线程池关闭前干一

《 Java并发编程从入门到精通》目录和序言

目 录 第一部分:线程并发基础   第1章 概念部分   1 1.1 CPU核心数.线程数 (主流cpu,线程数的大体情况说一下) 1 1.2 CPU时间片轮转机制 2 1.3 什么是进程和什么是线程 4 1.4 进程和线程的比较 5 1.5 什么是并行运行 7 1.6 什么是多并发运行 8 1.7 什么是吞吐量 9 1.8  多并发编程的意义及其好处和注意事项 10 1.9  分布式与并发运算关系 11 1.10 Linux和Window多并发可以采取不的一样机制(apache和tomcat?

《 Java并发编程从入门到精通》第5章 多线程之间交互:线程阀

作者:张振华    购买链接:天猫商城 (投入多少,收获多少.参与多深,领悟多深,京东,亚马逊,当当均有销售.)   5.1 线程安全的阻塞队列BlockingQueue (1)先理解一下Queue.Deque.BlockingQueue的概念: Queue(队列) :用于保存一组元素,不过在存取元素的时候必须遵循先进先出原则.队列是一种特殊的线性表,它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作.进行插入操作的端称为队尾,进行删除操作的端称为队头.队列中没有

《 Java并发编程从入门到精通》 常见的内存溢出的三种情况

作者:张振华    购买链接:天猫商城  JD商城  当当书店 鸟欲高飞先振翅,人求上进先读书.本文是原书的第9章 线程的监控及其日常工作中如何分析里的9.3.3节常见的内存溢出的三种情况. 3. 常见的内存溢出的三种情况: 1)JVM Heap(堆)溢出:java.lang.OutOfMemoryError: Java heap space JVM在启动的时候会自动设置JVM Heap的值, 可以利用JVM提供的-Xmn -Xms -Xmx等选项可进行设置.Heap的大小是Young Gene

《Java并发编程从入门到精通》显示锁Lock和ReentrantLock

作者:张振华    购买链接:天猫商城  JD商城  当当书店   显示锁Lock和ReentrantLock Lock是一个接口提供了无条件的.可轮询的.定时的.可中断的锁获取操作,所有加锁和解锁的方法都是显式的.包路径是:java.util.concurrent.locks.Lock.核心方法是lock(),unlock(),tryLock(),实现类有ReentrantLock, ReentrantReadWriteLock.ReadLock, ReentrantReadWriteLock

Java网络编程从入门到精通

Hibernate从入门到精通(十一)多对多双向关联映射 Hibernate从入门到精通(十)多对多单向关联映射 Hibernate从入门到精通(九)一对多双向关联映射 Hibernate从入门到精通(八)一对多单向关联映射 Hibernate从入门到精通(七)多对一单向关联映射 Hibernate从入门到精通(六)一对一双向关联映射 Hibernate从入门到精通(五)一对一单向关联映射 Hibernate从入门到精通(四)基本映射 Hibernate从入门到精通(三)Hibernate配置文

Java网络编程从入门到精通(34)

Java网络编程从入门到精通(34):读写缓冲区中的数据---使用get和put方法按顺序读写单个数据 对于缓冲区来说,最重要的操作就是读写操作.缓冲区提供了两种方法来读写缓冲区中的数据:get.put方法和array方法.而get.put方法可以有三种读写数据的方式:按顺序读写单个数据.在指定位置读写单个数据和读写数据块.除了上述的几种读写数据的方法外,CharBuffer类还提供了用于专门写字符串的put和append方法.在本文及后面的文章中将分别介绍这些读写缓冲区的方法. 虽然使用all

Java网络编程从入门到精通 (9):使用isXxx方法判断地址类型

本文为原创,如需转载,请注明作者和出处,谢谢! 上一篇:Java网络编程从入门到精通(8):用getAddress方法获得IP地址     IP地址分为普通地址和特殊地址.在前面的文章中所使用的大多数都是普通的IP地址,在本文中将介绍如何利用InetAddress类提供的十个方法来确定一个IP地址是否是一个特殊的IP地址. 一.isAnyLocalAddress方法     当IP地址是通配符地址时返回true,否则返回false.这个通配符地址对于拥有多个网络接口(如两块网卡)的计算机非常拥有

Java网络编程从入门到精通(34):读写缓冲区中的数据---使用get和put方法按顺序读写单个数据

本文为原创,如需转载,请注明作者和出处,谢谢! 上一篇:Java网络编程从入门到精通(33):非阻塞I/O的缓冲区(Buffer)     对于缓冲区来说,最重要的操作就是读写操作.缓冲区提供了两种方法来读写缓冲区中的数据:get.put方法和array方法.而get.put方法可以有三种读写数据的方式:按顺序读写单个数据.在指定位置读写单个数据和读写数据块.除了上述的几种读写数据的方法外,CharBuffer类还提供了用于专门写字符串的put和append方法.在本文及后面的文章中将分别介绍这