初步学习Java并发中的锁机制

来源:互联网 发布:c语言6.0下载 编辑:程序博客网 时间:2024/05/29 11:47

锁的功能

在java并发中,加锁可以保证线程的安全性,解决竞态条件问题。

竞态条件

某个计算的正确性取决于多个线程的交替执行时序。

常见类型:1. 先检查后执行(包括延时初始化)

                  2. 读取 - 修改 - 写入 操作

几种synchronized关键字的使用方式

1. 加在函数上

public class Test {private int count;public static void main(String[] args) {new Test().run();}private void run() {for (int i = 0; i < 1000; i++)new Thread() {@Overridepublic void run() {addCount();}}.start();System.out.println("count = " + count);}private synchronized void addCount() {count++;}}

这个锁加在了addCount函数前面,锁定的是Test实例出的对象

如果使用AtomicInteger,就不需要加锁操作


2. synchronized 代码块

    1. synchronized(this){} 锁定对象

    2. synchronized(A.class){} 锁定Test.class实例出的所有对象

public class Test2 {private int count;public static void main(String[] args) {new Test2().run();}private void run() {for (int i = 0; i < 3; i++)new Thread() {@Overridepublic void run() {new A().print(getName());}}.start();}}class A {public void print(String threadName) {synchronized (A.class) {for (int i = 0; i < 5; i++)System.out.println(threadName + "  " + i);}}}
虽然在Test2.run中,每个线程持有的是不同的对象,但是由于锁定的是class,输出是
      Thread-0  0      Thread-0  1      Thread-0  2      Thread-0  3      Thread-0  4      Thread-2  0      Thread-2  1      Thread-2  2      Thread-2  3      Thread-2  4      Thread-1  0      Thread-1  1      Thread-1  2      Thread-1  3      Thread-1  4

    3.   synchronized(某个变量){}

          在这种情况下,代码块会调用变量内部的锁,因此这个变量不能是原始类型(int,double等)

public class Test2 {private A a; public static void main(String[] args) {new Test2().run();} private void run() {a = new A();for (int i = 0; i < 1000; i++)new Thread() {@Overridepublic void run() {addCount();System.out.println(a.get());}}.start();}private void addCount() {synchronized(a) { // 使用的是a的锁a.addCount();}}}class A {private int count;public void addCount() {count++;}public int get() {return count;}}

死锁

当一个线程获取到锁后始终不退出时,其他的线程就只能一直等待

public class Test {private A a = new A();public static void main(String[] args) {new Test().run();}private void run() {new Thread() {@Overridepublic void run() {System.out.println("Thread A run");a.printA();}}.start();new Thread() {@Overridepublic void run() {System.out.println("Thread B sleep");try {sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Thread B try printB");a.printB();}}.start();}}class A {public synchronized void printA() {while(true) {// 这里死循环,Thread A 获取锁后不退出}}public synchronized void printB() {System.out.println("A, printB");}}

输出为:

Thread A run
Thread B sleep
Thread B try printB

这里给一个对比

public class Test {private A a = new A();public static void main(String[] args) {new Test().run();}private void run() {new Thread() {@Overridepublic void run() {System.out.println("Thread A run");                                while(true) {a.printA();}}}.start();new Thread() {@Overridepublic void run() {System.out.println("Thread B sleep");try {sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Thread B try printB");a.printB();}}.start();}}class A {public synchronized void printA() {}public synchronized void printB() {System.out.println("A, printB");}}

修改的部分为Thread A run函数的实现和A class中的printA函数,即将printA函数中的死循环移到了Thread A run函数中

输出为:

Thread A run
Thread B sleep
Thread B try printB
A, printB