参考:http://blog.csdn.net/zhangerqing/article/details/8284609
想必大家都知道线程安全问题:如果一个对象的状态是可变的,并且他有是共享的,可以被多个线程同时方案,则存在线程安全问题。
对于此类问题,解决方法主要有三种:1. 进制跨线程访问变量
2. 使状态变量为不可变(前两个方法咱就不考虑了,因为他实际上是放弃 了多线程)
3. 使用同步
a. 是操作原子性:比如value++就是一个非原子性的操作,他是先取值,再加1,最后再赋值。存在线程安全问题。使用java.util.concurrent.atomic包的方法可以保证原子性(atomic是如何保证原子性的有待研究),之后呈上一个线程安全的自增序列算法给大家。
public String nextLastSequence()
{
Long value = atomic.getAndIncrement();
if(value > max)
{
for(;;)
{
if(atomic.compareAndSet(value+1, min))
{
value = atomic.getAndIncrement();
break;
}
else{
value = atomic.getAndIncrement();
if(value <= max)
{
break;
}
}
}
}
return Filler(String.valueOf(value));
}
b. 加锁——内部锁
c. 加锁——显示锁
d. 加锁——重进入和读写锁不太理解
e. 可见性和过期数据概念
f. volatile变量概念及使用场景
4. 线程同步的几种实现以及对比
/**
*
*/
package com.demo;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author Maggie
*
*/
public class AtomicCounter implements Runnable
{
private final AtomicInteger count = new AtomicInteger(0);
int count1 = 0;
ReentrantLock lock = new ReentrantLock();
public void run()
{
while(true)
{
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
/**
* 同步方法
* 1. 内部锁:synchronized
* 1) 获取锁的线程执行完了代码块,然后线程会释放对锁的真有;
* 2) 线程执行发生异常,此时JVM会让线程自动释放锁。
* 但是,缺点:
* 如果这个获取锁的线程由于要等待IO或者其他原因(比如调用sleep方法)被阻塞了,
* 但是又没有释放锁,其他线程只能干巴巴的等待,这样是很不好的。
* 但是这种情况显示锁:Lock就可以办到,接下来也会介绍Lock
*/
// synchronized (this) {
// System.out.println(Thread.currentThread().getName()
// + ":" + count1++);
// }
/**
* 2. 原子操作:atomic
* 这里使用atomic保证了计数是原子性操作,但是System.out.println时
* 非原子性操作,所以会出现下面这种情况,但是数字肯定是不会重复的
*
* Thread-1:1
* Thread-2:3
* Thread-3:4
* Thread-0:2
* Thread-1:6
* Thread-2:5
*/
// System.out.println(Thread.currentThread().getName()
// + ":" + count.incrementAndGet());
/**
* 3. 显示锁
* 相比起synchronized的优缺点
* 优点:定时所的等待,可中断锁的等待,公平性,以及实现非块结构的锁
* 缺点:复杂,易错,还会存在忘记释放锁的风险。
*
* 注意:ReentrantLock lock = new ReentrantLock();应该提前到
* 为全局变量,如果放在了这个下面作为局部变量就失去了锁的作用了,会出现下面情况
*
* 得到了锁
* 得到了锁
* Thread-2:0
* 释放了锁
* Thread-0:1
* 释放了锁
*/
// ReentrantLock lock = new ReentrantLock(); // 放在这里没用,
lock.lock();
try {
System.out.println("得到了锁");
System.out.println(Thread.currentThread().getName()
+ ":" + count1++);
} finally {
lock.unlock();
System.out.println("释放了锁");
}
}
}
public static void main(String[] args)
{
AtomicCounter counter = new AtomicCounter();
Thread t1 = new Thread(counter);
Thread t2 = new Thread(counter);
Thread t3 = new Thread(counter);
Thread t4 = new Thread(counter);
t1.start();
t2.start();
t3.start();
t4.start();
}
}