线程不安全会发生什么问题?线程不安全会发生什么问题?线程不安全会发生什么问题?
Java非线程安全与线程安全 ArrayList和Vector的区别在哪里? HashMap和HashTable区别在哪里? StringBuilder和StringBuffer区别在哪里? 张口即答,区别在于前者是非线程安全的,后者是线程是线程安全的。 那么...

Java非线程安全与线程安全

- 首先来看几个问题
ArrayList和Vector的区别在哪里?
HashMap和HashTable区别在哪里?
StringBuilder和StringBuffer区别在哪里?
张口即答,区别在于前者是非线程安全的,后者是线程是线程安全的。
那么,到底什么叫线程安全?什么叫线程不安全?线程安全不安全的原因是什么?怎么实现线程安全?线程安全和非线程安全有
什么区别?分别在什么情况下使用?
一、线程安全
是指你的代码所在的进程中有多个线程同时运行,而这些线程可能会同时运行这段代码,如果每次运行的代码结
果和单线程运行的结果是一样的,而且其他变量的值和预期的也是一样的,那么就是线程安全的。
或者说:一个类或者程序所提供的接口对于线程来说是原子操作或者多个线程之间的切换不会导致该接口的执行结果存在二义性,
也就是说我们不用考虑同步的问题。
线程安全问题都是由全局变量及静态变量引起的。
若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行
写操作,一般都需要考虑线程同步,否则就可能影响线程安全。
二、非线程安全
是不提供代码数据访问保护,可能出现多个线程先后访问更改数据造成所得的数据是脏数据。*(脏数据是表示一个数据已经
被修改,但是还没有保存或进一步的处理。例如你操作数据库修改某一字段内容,在你修改了但还没commit时,另一线程在读取这
数据,他读取的就是你修改前的数据,但事实上你已经修改了,这就是脏数据了。)*在多个线程同时访问同一个对象时会发生数据
错误 不完整等情况时 那就是线程不安全,不会发生上续错误时是线程安全的,一般采用锁机制。
三、线程安全出现的根本原因
存在两个或者两个以上的线程对象共享同一个资源;
多线程操作共享资源代码有多个语句。
存在竞争的线程不安全,不存在竞争的线程就是安全的
四、怎么实现线程安全
1、synchronized
同步代码块、同步方法
synchronized关键字,就是用来控制线程同步的,保证我们的线程在多线程环境下,不被多个线程同时执行,确保我们数据的完
整性,使用方法一般是加在方法上。
public class ThreadDemo { int count = 0; // 记录方法的命中次数 public synchronized void threadMethod(int j) { count++ ; int i = 1; j = j + i; } }
这样就可以确保我们的线程同步了,同时这里需要注意一个大家平时忽略的问题,首先synchronized锁的是括号里的对象,而不是代码,其次,对于非静态的synchronized方法,锁的是对象本身也就是this。
当synchronized锁住一个对象之后,别的线程如果想要获取锁对象,那么就必须等这个线程执行完释放锁对象之后才可以,否则一直处于等待状态。
注意点:虽然加synchronized关键字,可以让我们的线程变得安全,但是我们在用的时候,也要注意缩小synchronized的使用范围,如果随意使用时很影响程序的性能,别的对象想拿到锁,结果你没用锁还一直把锁占用,这样就有点浪费资源。
2.Lock
Lock锁机制, 通过创建Lock对象,采用lock()加锁,unlock()解锁,来保护指定的代码块
五、分别在什么情况下使用
线程安全是多线程操作同一个对象不会有问题;
非线程安全是指多线程操作同一个对象可能会出现问题;
线程安全会导致性能的降低。
如果是多个线程操作同一个对象,那么使用线程安全的Vector;否则,就使用效率更高的ArrayList。
PS(非线程安全并非不安全)
非线程安全并不是多线程环境下就不能使用。
本文作为多线程编程的第一篇文章,将从一个简单的例子开始,带你真正从代码层次理解什么是线程不安全,以及为什么会出现线程不安全的情况。文章中将提供一个完整的线程不安全示例,希望你可以跟随文章,自己真正动手...

简介

本文作为多线程编程的第一篇文章,将从一个简单的例子开始,带你真正从代码层次理解什么是线程不安全,以及为什么会出现线程不安全的情况。文章中将提供一个完整的线程不安全示例,希望你可以跟随文章,自己真正动手运行一下此程序,体会一下多线程编程中必须要考虑的线程安全问题。

一.什么是线程安全

《Java Concurrency In Practice》作者Brian Goetz的定义:“当多个线程访问一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替执行,也不需要进行额外的同步或者在调用方进行任何其他的协调操作,调用这个对象的行为都可以获得正确的结果,那这个对象是线程安全的。
为什么不把所有操作都做成线程安全的?
实现线程安全是有成本的,比如线程安全的程序运行速度会相对较慢、开发的复杂度也提高了,提高了人力成本。

二.从经典的线程不安全的示例开始

经典案例: 两个线程,共同读写一个全局变量count,每个线程执行10000次count++,count的最终结果会是20000吗,在心中猜测一下运行结果?
经典案例的代码实现:
package com.study.synchronize.object; /** * 线程不安全案例:两个线程同时累加同一个变量,结果值会小于实际值 */ public class ConcurrentProblem implements Runnable {	private static ConcurrentProblem concurrentProblem = new ConcurrentProblem();	private static int count;	public static void main(String[] args) {	Thread thread1 = new Thread(concurrentProblem);	Thread thread2 = new Thread(concurrentProblem);	thread1.start();	thread2.start();	try {	// 等待两个线程都运行结束后,再打印结果	thread1.join();	thread2.join();	} catch (InterruptedException e) {	e.printStackTrace();	}	//期待结果是20000,但是结果会小于这个值	System.out.println(count);	}	/**	* 多线程问题原因:count++这行代码要分三步执行;1:读取;2:修改;3:写入。	* 在这三步中,任何一步都可能被其他线程打断,导致值还没来得及写入,就被其他线程读取或写入,这就是多线程并行操作统一变量导致的问题。	*/	@Override	public void run() {	for (int k = 0; k