class MyRunnable implements Runnable{
private int j=5;
@Override
public void run() {
synchronized(this){ //加锁的为当前对象
for(int i=0;i<5;i++){
try {
Thread.sleep(100);
System.out.println(Thread.currentThread().getName()+" loop "+i);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
Runnable runnable = new MyRunnable();
Thread t1 = new Thread(runnable,"t1");
Thread t2 = new Thread(runnable,"t2");
t1.start();
t2.start();
}
}
//输出结果如下,即当t1线程占用锁对象时,t2线程是无法进入同步代码块中的,只有等t1线程释放掉所对象之后才能够进入
t1 loop 0
t1 loop 1
t1 loop 2
t1 loop 3
t1 loop 4
t1 loop 5
t1 loop 6
t1 loop 7
t1 loop 8
t1 loop 9
t2 loop 0
t2 loop 1
t2 loop 2
t2 loop 3
t2 loop 4
t2 loop 5
t2 loop 6
t2 loop 7
t2 loop 8
t2 loop 9
synchronized的底层原理的底层原理:
同步语句块的情况:
public class SynchronizedDemo {
public void method() {
synchronized (this) {
System.out.println("synchronized 代码块");
}
}
}
同步语句块的实现使用的是同步语句块的实现使用的是monitorenter和和monitorexit指令指令,其中monitorenter指同步代码块的开始位置,而monitorexit是同步代码块的结束位置。当执行monitorenter的时候,线
程试图获取锁对象的monitor(monitor对象是存在java对象中的对象头中,每个java对象都具有),获取到时将锁计数器设为1,当其余线程获取锁时,检测到锁的计数器为1则被阻
塞。当执行monitorexit时将锁释放,锁计数器-1变为0;
synchronized修饰实例方法时锁对象为实例对象,修饰静态方法时锁对象为类对象;修饰代码块时指定锁对象
修饰实例方法的时候:
public class SynchronizedDemo2 {
public synchronized void method() {
System.out.println("synchronized 方法");
}
}
修饰方法的时候并没有monitorenter和monitorexit指令,取而代之是 ACC_SYNCHRONIZED 标识,该标识指明了该方法是一个同步方法,jvm通过该标识来辨别一个方法是否声明为
同步方法,从而执行相应的同步调用。
2、实例锁跟全局锁:实例锁即同步代码块或方法是非静态,锁对象为实例对象,而全局锁是存在于静态方法或静态代码块中的,是通过类来创建锁(static synchronized)
3、wait方法和notify方法:存在于同步代码块中,当调用wait方法时,始当前线程进入等待阻塞状态,并释放当前的锁对象,直到其余线程调用notify方法或者notifyAll方法—
wait(long time)等待某段时间后重新运行,即使没有线程调用notify方法。
4、join的方法:等待子线程(即调用join方法的那个线程类)执行完成之后再执行父线程
public class JoinTest {
public static void main(String[] args) {
class ThreadA extends Thread{
public ThreadA(String name){
super(name);
}
@Override
public void run() {
System.out.println("start "+this.getName());
for(int i=0;i<1000000000;i++)
;
System.out.println("finish "+ this.getName());
}
}