/**
* @Author xty
* @Description
* @Date 19:31 2018/11/12
*/
public class Counter {
private int count;
public void add(){
try{
for (int i = 0;i<200;i++){
Thread.sleep(100);
this.count++;
System.out.println(this.count);
}
}catch (Exception e ){
e.printStackTrace();
}
}
}
/**
* @Author xty
* @Description
* @Date 19:33 2018/11/12
*/
public class Test {
public static void main(String[] args) {
final Counter counter = new Counter();
new Thread(new Runnable() {
@Override
public void run() {
counter.add();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
counter.add();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
counter.add();
}
}).start();
}
}
新建两个类,运行之后总数并没有到3*200 ,因为产生了并发问题。
解决方法1.
/**
* @Author xty
* @Description
* @Date 19:31 2018/11/12
*/
public class Counter {
private int count;
public synchronized void add(){
try{
for (int i = 0;i<200;i++){
Thread.sleep(100);
this.count++;
System.out.println(this.count);
}
}catch (Exception e ){
e.printStackTrace();
}
}
}
虽然结果对了,但是使用了synchronized 效率极其低下。
解决方法2.
/**
* @Author xty
* @Description
* @Date 19:31 2018/11/12
*/
public class Counter {
private int count;
public void add(){
try{
for (int i = 0;i<200;i++){
Thread.sleep(100);
synchronized(this) {
this.count++; //竞争条件
System.out.println(this.count);
}
}
}catch (Exception e ){
e.printStackTrace();
}
}
}
将synchronized加入到关键部位(竞争条件),效率有所提升。
解决方法3.
/**
* @Author xty
* @Description
* @Date 19:31 2018/11/12
*/
public class Counter {
//原子性
private AtomicInteger count = new AtomicInteger();
public void add(){
try{
for (int i = 0;i<200;i++){
Thread.sleep(100);
count.incrementAndGet();
System.out.println(this.count);
}
}catch (Exception e ){
e.printStackTrace();
}
}
}
使用AtomicInteger 类。输出顺序并没有保证,但是最后的结果是正确的。因为排队效率会低。
可重入锁:
一个线程获取它本生已经持有的锁,这是可以成功的。我们知道多个线程同时抢占同一个锁它们是失败的。因为它们之间是互斥的。但是呢,一个线程再次获取一个自己已经拿过的锁是可以成功的,那么它是能够成功的。
public class Widget {
public synchronized void doSth(){
}
}
public class ChildWidget extends Widget {
@Override
public synchronized void doSth() {
super.doSth();
}
}
public class Test {
public static void main(String[] args) {
Widget w = new ChildWidget();
w.doSth();
}
}
子类和父类调用的锁都是w这个对象,因此这种方式叫做内部锁的可重入机制,也叫可重入锁。