Synchronized考得比较多,边学边总结。错误之处,请不吝赐教
1 Synchronized
1) 锁的作用域
每个class和instance都有一把属于自己的锁,当有synchronized关键字时,要执行方法时,必须拿到相应的锁。
class: 当synchronized被static修饰时,它是锁定类
instance: 当synchronized修饰方法时,它锁定此方法的所在的对象。如果有多个方法被synchronized修饰,那么一个synchronized执时,其它的synchronized方法全部阻塞,等待被锁定的对象释放。
例如:
public class StaticSynchronized implements Runnable {
static int id = 1;
public void run() {
try {
id = 1 - id;
if(id == 0) { pick(); }
else { release(); }
}catch(Exception e) { }
}
//static synchronized锁定类;
private static synchronized void pick() throws Exception {
System.out.print("P "); System.out.print("Q ");
}
//synchronized锁定对象;
private synchronized void release() throws Exception {
System.out.print("R "); System.out.print("S ");
}
public static void main(String[] args) {
StaticSynchronized st = new StaticSynchronized();
new Thread(st).start();
new Thread(st).start();
}
}
Possible Output:
// all combination that satisfies the following rules: 1) P is ahead of Q 2) R is ahead of S 3) PQ and RS will be printed only once
P Q R S
P R S Q
P R Q S
.....
解析:
虽然有2个synchronized的方法,但一个锁定类;一个锁定对象,毫不冲突
例如二:
今天看到群里有人说了个小笑话,说他去超市,有个小孩当着他面问妈妈,这个人是男是女?
我一直在找个原型,模拟一些多线程实例,就这个小笑话,模拟一下类级锁吧。
package com.ocjp.testThread;
/*
* static synchronized method, it will lock the class;
*/
public class TestSynchoronzied{
public static void main(String[] args) {
MyThread t1 = new MyThread();
t1.p = new Person(1,"adult");
MyThread t2 = new MyThread();
t2.p = new Person(2,"kid");
System.out.println("test synchronized to lock an object");
t1.start(); //t1 will call MyThread.shopping();
//isGoodPerson() cannot be invoked till shopping() is fully completed;
//Though shopping() even sleep(1000) during running; but this method will hold the class lock; Other methods who need the same class lock have to wait;
t2.start(); //t2 will call MyThread.isGoodPerson();
}
}
class MyThread extends Thread {
Person p;
public void run(){
if(p.getPid()==1){
shopping(p);
}else{
isGoodPerson(p);
}
}
static synchronized void isGoodPerson(Person p){
// static synchronized void isGoodPerson(){
System.out.println("kid asks his mom: is this Person good or bad?");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Mom answered: I think he is bad");
}
static synchronized void shopping(Person p){
System.out.println("Person is shopping");
}
}
class Person{
private int pid;
private String pname;
// getter & setter(); constructor();
public int getPid() {
return pid;
}
public void setId(int id) {
this.pid = id;
}
public String getPname() {
return pname;
}
public void setPname(String name) {
this.pname = name;
}
public Person(int id, String name) {
super();
this.pid = id;
this.pname = name;
}
public Person(){}
}
Output:
kid asks his mom: is this Person good or bad? //converstation between mom and kid cannot be interrupted;
Mom answered: I think he is bad
Person is shopping
or:
Person is shopping
kid asks his mom: is this Person good or bad?
Mom answered: I think he is bad
2 多线程中阻塞状态的方法
sleep(); 静态方法,无论哪个对象调,都相当于Thread.sleep(),让当前线程处于睡眠状态,让出CPU使用权,但不交出锁...有异常
yield(); 调用它的线程,让出一次CPU使用权,基本不影响时间片的分配。。。
join(); 调用它的线程优先执行,其它线程处于阻塞状态,相当于变成单线程;如果传了参数,那么在指定的时间范围内,如果调用它的线程还活着,就进入多线线程状态;
模拟代码:
package com.ocjp.testThread;
public class TestJoin {
public static void main(String[] args) {
Reader r = new Reader();
Thread t = new Thread(r);
t.start();
// join()是给调用它的线程更多时间片,让别的线程排在它后面执行,相当于变成了单线程;
// join()有异常,要处理;
try {
// 给t分配了0.1秒的时间,去完成;0.1秒后又恢复多线程;
t.join(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
for(int i=0;i<100;i++){
System.out.println(Thread.currentThread().getName());
}
}
}
class Reader implements Runnable{
@Override
public void run() {
for(int i=0;i<100;i++){
System.out.println(Thread.currentThread().getName());
// try {
// Thread.sleep(100);
// } catch (InterruptedException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
}
}
}