synchronized 基本用法
常见三种使用方式
1)普通同步方法,锁是当前实例;
2)静态同步方法,锁是当前类的Class实例,Class数据存在永久代中,是该类的一个全局锁;
3)对于同步代码块,锁是synchronized括号里配置的对象。
方式一 普通方法通过synchronized修饰
1)不采用synchronized 当创建两个线程对象 线程t1 t2中采用同一个实例化类对象 调用method方法 会交异步执行 互补影响
package cn.ac.bcc.sync; /** * 普通同步方法通过synchronized修饰 * @author Administrator * */ public class PtMethod { /** * 1)不采用synchronized修饰 * @param s */ public void method(String s){ if(s.equals("a")){ System.out.println(Thread.currentThread().getName()+": a"); try { Thread.sleep(3000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } }else{ System.out.println(Thread.currentThread().getName()+": b"); } } public static void main(String[] args) { //创建当前类对象实例 final PtMethod ptMethod = new PtMethod(); //创建线程 Thread t1 = new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub ptMethod.method("a"); } }); Thread t2 = new Thread(new Runnable(){ @Override public void run() { // TODO Auto-generated method stub ptMethod.method("b"); } }); t1.start(); t2.start(); } }
运行结果:
Thread-1: b
Thread-0: a
2)采用synchronized 当创建两个线程对象 线程t1 t2 中采用同一个实例化对象 调用synchronized修饰的method方法 method方法中线程睡眠一秒钟 当线程t1优先抢占到method方法的执行权时由于method方法被synchronized修饰 method方法被实例化对象ptMethod对象锁锁住 当t2线程同样是ptMethod实例化对象调用当前method方法 由于两个线程t1 t2 都采用的是同一个实例化对象ptMethod 对象锁 只有t1运行完成后 t2中线程中的ptMethod对象才能调用method方法。由于method中获取当前调用线程睡眠 t2要等t1中调用的method睡眠唤醒之后执行完方法才能执行。
public class PtMethod { /** * 1)采用synchronized修饰 * @param s */ public synchronized void method(String s){ if(s.equals("a")){ System.out.println(Thread.currentThread().getName()+": a"); try { Thread.sleep(3000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } }else{ System.out.println(Thread.currentThread().getName()+": b"); } } public static void main(String[] args) { //创建当前类对象实例 final PtMethod ptMethod = new PtMethod(); //创建线程 Thread t1 = new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub ptMethod.method("a"); } }); Thread t2 = new Thread(new Runnable(){ @Override public void run() { // TODO Auto-generated method stub ptMethod.method("b"); } }); t1.start(); t2.start(); } }
3)采用synchronized修饰 创建两个线程对象 创建当前类实例对象 ptMethod1 ptMethod2 t1线程运行ptMetod1 t2线程运行ptMethod2 对象分别调用mehod方法 运行结果如下 ,由于两个线程分别采用的是两个不同的实例对象 当两个实例对象调用method方法时 synchronized判断当前锁对象并不相同 所以里两个对象向都分别调用了method方法,而不需要等待
public class PtMethod { /** * 1)采用synchronized修饰 * @param s */ public synchronized void method(String s){ if(s.equals("a")){ System.out.println(Thread.currentThread().getName()+": a"); try { Thread.sleep(3000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } }else{ System.out.println(Thread.currentThread().getName()+": b"); } } public static void main(String[] args) { //创建当前类对象实例 final PtMethod ptMethod1 = new PtMethod(); final PtMethod ptMethod2 = new PtMethod(); //创建线程 Thread t1 = new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub ptMethod1.method("a"); } }); Thread t2 = new Thread(new Runnable(){ @Override public void run() { // TODO Auto-generated method stub ptMethod2.method("b"); } }); t1.start(); t2.start(); } }
运行结果:
Thread-0: a
Thread-1: b
二、synchronized修饰静态方法
采用synchronized 修饰的静态方法 两个线程通过不同的 类实例对象调用 这个方法 如何加锁 这是可以将该方法修改为static 方法 并synchronized修饰
public class SyncDemo { /** * 类方法 synchronized修饰 解决多个线程调用当前类不同实例采用同步锁方法 * @param s */ public static synchronized void method(String s){ if(s.equals("a")){ System.out.println(Thread.currentThread().getName()+": a"); try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } }else{ System.out.println(Thread.currentThread().getName()+": b"); } } public static void main(String[] args) { final SyncDemo syncDemo1 = new SyncDemo(); final SyncDemo syncDemo2 = new SyncDemo(); Thread t1 = new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub syncDemo1.method("a"); } }); Thread t2 = new Thread(new Runnable(){ @Override public void run() { // TODO Auto-generated method stub syncDemo2.method("b"); }}); t1.start(); t2.start(); } }
三、同步代码块
1)当两个并发线程同时访问一个对象的同步代码块synchronized(this),在某一时刻只有一条线程才能访问该同步代码块
public class SyncDemo1 implements Runnable { public static void main(String[] args) { SyncDemo1 syncDemo1 = new SyncDemo1(); new Thread(syncDemo1,"a").start();; new Thread(syncDemo1,"b").start();; } @Override public void run() { // TODO Auto-generated method stub System.out.println(Thread.currentThread().getName()+"执行开始run方法"); synchronized (this) { System.out.println(Thread.currentThread().getName()); } } }
运行结果: 当b抢到执行权只有b线程执行完成a线程才能继续执行
b执行开始run方法
b
a执行开始run方法
a
2)当一个线程访问object对象中的synchronized(this)同步代码块时,另一个线程可以访问object对象的非同步代码块
package cn.ac.bcc.sync; public class SyncDemo2 { public void method1(){ synchronized (this) { System.out.println(Thread.currentThread().getName()+"线程同步代码块"); } } public void method2(){ System.out.println(Thread.currentThread().getName()+"当两个线程访问同一个object 中的方法 一个线程访问线程同步方法 另一个可以方位object对象的非线程同步方法"); } public static void main(String[] args) { final SyncDemo2 syncDemo2 = new SyncDemo2(); //创建两个线程对象 Thread t1 = new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub syncDemo2.method1(); } },"t1"); Thread t2 = new Thread(new Runnable(){ @Override public void run() { // TODO Auto-generated method stub syncDemo2.method2(); } },"t2"); t1.start(); t2.start(); } }
3)当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。
package cn.ac.bcc.sync; public class SyncDemo2 { public void method1(){ synchronized (this) { System.out.println(Thread.currentThread().getName()+"线程同步代码块"); try { System.out.println(Thread.currentThread().getName()+"睡一会"); Thread.sleep(10000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public void method2(){ synchronized (this) { System.out.println(Thread.currentThread().getName()+"访问线程同步代码块"); } } public static void main(String[] args) { final SyncDemo2 syncDemo2 = new SyncDemo2(); //创建两个线程对象 Thread t1 = new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub syncDemo2.method1(); } },"t1"); Thread t2 = new Thread(new Runnable(){ @Override public void run() { // TODO Auto-generated method stub syncDemo2.method2(); } },"t2"); t1.start(); t2.start(); } }
运行结果:
t1线程同步代码块
t1睡一会
10秒后t2才能访问当前对象其他同步代码块修饰的方法
t1线程同步代码块
t1睡一会
t2访问线程同步代码块