上一节中介绍了线程安全的问题,这一节简单介绍下通过synchronized来解决线程安全问题。
public class MyRunnable implements Runnable {
private int index = 0;
private static Integer MAX_NUM = 1000;
private final Object LOCK = new Object();
@Override
public void run() {
while (true) {
synchronized (LOCK) {
if (index > MAX_NUM) {
break;
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "当前的值:" + index++);
}
}
}
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread t1 = new Thread(myRunnable, " 线程1");
t1.start();
Thread t2 = new Thread(myRunnable, " 线程2");
t2.start();
Thread t3 = new Thread(myRunnable, " 线程3");
t3.start();
}
***********加上synchronized同步代码块后,打印出来的结果跟我们预期一致*****************
线程3当前的值:998
线程2当前的值:999
线程2当前的值:1000
下面代码中synchronzied同步方法,结果也是符合相同。但是你会发现只有一个线程在执行。这是因为三个线程同时争抢资源,假设线程1获取到锁,其他两个线程会等待线程1释放锁。当线程1在run方法执行完毕后,此时index值已经为1000,其他两个线程获取锁后被直接break掉,导致实际只有一个线程在执行。
public class MyRunnable implements Runnable {
private int index = 0;
private static Integer MAX_NUM = 1000;
@Override
public synchronized void run() {
while (true) {
if (index > MAX_NUM) {
break;
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "当前的值:" + index++);
}
}
}
同步代码块和同步方法的区别:
同步方法默认使用this或者当前类做为锁。
public class SyncRunnable {
private Object LOCK = new Object()
;
public synchronized void test1() {
System.out.println("*************************");
try {
Thread.sleep(10_00);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("*end");
}
public synchronized void test2() {
System.out.println("================");
try {
Thread.sleep(10_00);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("=end");
}
}
public static void main(String[] args) {
SyncRunnable syncRunnable = new SyncRunnable();
Thread thread = new Thread() {
@Override
public void run() {
syncRunnable.test1();
}
};
Thread thread2 = new Thread() {
@Override
public void run() {
syncRunnable.test2();
}
};
thread.start();
thread2.start();
}
**********************************************
执行结果如下,获取cpu资源的线程执行完毕后,等待的线程才会继续执行。说明锁定的是当前类。
*************************
*end
================
=end
同步代码块可以选择以什么来加锁,比同步方法更精确,在加锁时也要尽量保证最小单位加锁我们可以选择只有会在同步发生同步问题的代码加锁,而并不是整个方法。
public class SyncRunnable {
private Object LOCK = new Object();
public void test3() {
System.out.println("****************");
synchronized (LOCK) {
try {
Thread.sleep(10_00);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("*end");
}
public void test4() {
System.out.println("================");
synchronized (LOCK) {
try {
Thread.sleep(10_00);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("=end");
}
}
public static void main(String[] args) {
SyncRunnable syncRunnable = new SyncRunnable();
Thread thread = new Thread() {
@Override
public void run() {
syncRunnable.test3();
}
};
Thread thread2 = new Thread() {
@Override
public void run() {
syncRunnable.test4();
}
};
thread.start();
thread2.start();
}
******************************
执行结果如下,同步发生同步问题的代码加锁,而并不是整个方法。
****************
================
*end
=end
同步方法使用synchronized修饰,而同步代码块使用synchronized(this){}修饰。
网友评论