1.synchronized关键字简介
synchronized简单来说就是一把隐形锁,可以系统调度,也可以自主调度。
线程控制的注意点:
/*
* synchronized在jdk1.6前是重量级锁,即映射到OS的线程控制,资源开销大,后改进成JVM上的线程控制,成了轻量级锁
* --------
* 注意:Thread的线程是由你启动的那个implements Runnable的类控制的,如果你Thread传入的对象不是同一个
* 那么你不同的线程访问到的数据就不一样了,即资源不共享,除非是静态资源
* synchronized如果锁的是类(静态)级别的,那么就是所有对象共用。不然范围就只是在该对象。
* --------
* 可以为代码区加锁,方法加锁,数据加锁。
* --------
* synchronized是通过监视器达到线程管理的,这种lock通过Monitor形成阻塞队列自动调度管理
* 所以在调用wait和notify时要注意对调用对象进行锁定,不然无法调度阻塞队列管理
* */
2.synchronized调用实例
示范不同加锁方式:synchronized可以对代码区加锁,方法加锁,数据加锁,而wait()和notify()也是Object类的方法,所以适用性很广,但是要进行对象锁定比较麻烦。
自动阻塞唤醒调度示例:(当被锁定的代码发生竞争时,自动阻塞,直到运行线程结束释放锁,自动唤醒阻塞队列中的线程。注意,同时不被锁定的资源可以共享)
public class SExam implements Runnable {
private Byte[] lock = new Byte[0];
private int count = 0;
private static int scount = 0;
@Override
public void run() {
for (int i = 0; i < 2; i++) {
// lock the codeArea, stop for 1s
synchronized (this) {
try {
read_code();
Thread.sleep(1000);
} catch (Exception e) {
System.out.println(e);
}
}
// entity method lock, stop for 1s
try {
write();
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// class method lock, stop for 1s
try {
sWrite();
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// lock the code for lock the data, stop for 1s
synchronized (lock) {
try {
read_data();
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public void read_code() {
System.out.println(Thread.currentThread().getName() + " to the codeAreaLock -- count read: " + count);
}
public void read_data() {
System.out.println(Thread.currentThread().getName() + " to the dataLock -- count read: " + count);
}
public synchronized void write() {
count++;
System.out.println(Thread.currentThread().getName() + " to the entityLock -- count read: " + count);
}
public static synchronized void sWrite() {
scount++;
System.out.println(Thread.currentThread().getName() + " to the classLock -- scount read: " + scount);
}
}
wait即释放锁,进入休眠,等待唤醒。notify即进行队列线程唤醒,占有锁。
notify是根据monitor管理的队列随机唤醒,所以要区分好唤醒哪个队列的线程。(还有notifyAll()在主线程上也较为常用)
手动调度阻塞唤醒示例:(模拟对资源的同步提供与获取)
public class SWaitAndNotify implements Runnable {
private Byte[] lock = new Byte[0];
private int source = 0;
private Integer full = new Integer(0), empty = new Integer(0);
@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
offer();
Thread.sleep(1000);
require();
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void offer() throws InterruptedException {
synchronized (lock) {
synchronized (full) {
if (source >= 10)
full.wait();
}
source++;
System.out.println(Thread.currentThread().getName() + ":+1=" + source);
synchronized (empty) {
empty.notify();
}
}
}
public void require() throws InterruptedException {
synchronized (lock) {
synchronized (empty) {
if (source == 0)
empty.wait();
}
source--;
System.out.println(Thread.currentThread().getName() + ":-1=" + source);
synchronized (full) {
full.notify();
}
}
}
}