JAVA中对同步控制主要通过synchronized关键字
wait() notify()和notifyAll()方法
1.synchronized 的用法
每个类实例对应一把锁,每个synchronized方法都必须获得调用该方法的类实例的锁才能执行,否则发生线程阻塞
方法一旦执行,就独占锁,直到该方法返回时,才释放锁,此后被阻塞的线程才能获得该锁。
A . 声明方法时,放在范围操作符和返回值之间。
作用:表示一次只能有一个线程进入该方法,其他的线程想在此时调用这个方法,只能是排队等待
只有当当前的线程执行完该方法以后,其他的线程才能进入。
B. synchronized代码块
格式:synchronized(variable){
code;
}
一次只能有一个线程进入该代码块
C . synchronized(object)
格式:synchronized(object o){
code;
}
线程获得的是对象锁。对象锁会在下一篇笔记里详细学习,到时候再贴上链接
D . synchronized(Class)
synchronized的参数是类,只要线程进入,则该类中的所有操作都不能进进行,包括静态变量和静态方法。
synchronized代码块示例:
package synchronizedTest;
public class Tasks implements Runnable{
public void taskA() {
System.out.println(Thread.currentThread().getName()+"进入taskA");
synchronized (this) {
System.out.println(Thread.currentThread().getName()+"synchronized in taskA()");
try {
//用sleep()模拟任务耗时
Thread.sleep(2000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void taskB() {
System.out.println(Thread.currentThread().getName()+"进入taskB");
synchronized (this) {
System.out.println(Thread.currentThread().getName()+"synchronized in taskB()");
//用sleep()模拟任务耗时
try {
Thread.sleep(2000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
@Override
public void run() {
// TODO Auto-generated method stub
taskA();
taskB();
}
}
package synchronizedTest;
public class Test {
public static void main(String [] args){
Runnable tasks1= new Tasks();
Thread th1=new Thread(tasks1);
Thread th2=new Thread(tasks1);
th1.start();
th2.start();
}
}
输出结果:
Thread-0进入taskA
Thread-0synchronized in taskA()
Thread-1进入taskA
Thread-1synchronized in taskA()
Thread-0进入taskB
Thread-1进入taskB
Thread-0synchronized in taskB()
Thread-1synchronized in taskB()
这个例子想表达的意思是:
当两个并发线程访问同一个对象中的synchronized同步代码块时,一个时间内只能有一个线程得到执行,另一个线程必须等待当前线程完成后才能得到执行。然而,当一个线程访问synchronized同步代码块时,另一个线程仍然可以访问该对象的非synchronized同步代码块。这也是为什么结果中当Thread-0和Thread-1都可以打印出“进入代taskB”语句。
wati(),notify()和 notifyAll()
调用任意对象的wait()方法,都会导致线程阻塞,并且该对象上的锁被释放
调用任意对象的notify()方法,则会随机选择一个阻塞状态的进程,并解除该线程的阻塞状态。
注意:
1.这两个方法是每个对象都具有的,而不是只属于线程类。
2.如果要把notify和wait方法放在一起用的话,必须先调用notify后调用wait,因为如果调用完wait,那么那个线程就会进入等待队列,该线程就已经不是current thread了。
3.调用wait()方法前的判断最好用while,而不用if;while可以实现被wakeup后thread再次作条件判断;而if则只能判断一次。
4.除了 notify(),还有一个方法 notifyAll() 也可起到类似作用,唯一的区别在于,调用 notifyAll() 方法将把因调用该对象的wait() 方法而阻塞的所有线程一次性全部解除阻塞。当然,只有获得锁的那一个线程才能进入可执行状态。
.