互斥锁解决售票超卖问题:
package com.edu.threaduse; /** * @author mtl121 * @version 1.0 */ public class sellTicket { public static void main(String[] args) { Ticket2 ticket1 = new Ticket2(); new Thread(ticket1).start(); new Thread(ticket1).start(); new Thread(ticket1).start(); } } class Ticket2 implements Runnable{ int count = 100; boolean loop = true; @Override public void run() { while(loop){ sell(); } } void sell(){ synchronized(this){ if(count <= 0){ System.out.println("售票结束"); loop = false; return ; } count --; System.out.println(String.format("还剩下%d张票", count) + Thread.currentThread().getName()); } } } class Ticket1 implements Runnable{ int count = 100; boolean loop = true; @Override public void run() { while(loop){ sell(); } } synchronized void sell(){ if(count <= 0){ System.out.println("售票结束"); loop = false; return; } count --; System.out.println(String.format("还剩下%d张票", count) + Thread.currentThread().getName()); } }
package com.edu.threaduse; /** * @author mtl121 * @version 1.0 */ public class sellTicket { public static void main(String[] args) { Ticket2 ticket1 = new Ticket2(); new Thread(ticket1).start(); new Thread(ticket1).start(); new Thread(ticket1).start(); } } class Ticket2 implements Runnable{ int count = 100; boolean loop = true; @Override public void run() { while(loop){ sell(); } } //同步代码块,互斥锁是在同步代码块中 /* 静态方法中的同步代码块,加锁: public static void m2(){ //注意这里写的是类本身 synchronized (Ticket2.class){ System.out.println("m2"); } } * */ void sell(){ //同步代码块的锁可以不是当前对象,也可以是其他对象 synchronized(this){ if(count <= 0){ System.out.println("售票结束"); loop = false; return ; } count --; System.out.println(String.format("还剩下%d张票", count) + Thread.currentThread().getName()); } } } class Ticket1 implements Runnable{ int count = 100; boolean loop = true; @Override public void run() { while(loop){ sell(); } } //同步方法(静态的)的锁为当前类本身 /* public synchronized static void m1(){}//该锁就是加在Ticket1.class上 * */ //同步方法,的锁加在this对象 synchronized void sell(){ if(count <= 0){ System.out.println("售票结束"); loop = false; return; } count --; System.out.println(String.format("还剩下%d张票", count) + Thread.currentThread().getName()); } }
互斥锁
注意事项:
① 同步方法如果没有用static修饰,默认锁对象是this
② 如果方法用static修饰,默认锁对象为 当前类.class
③ 建议使用方法中的同步代码块,而不是同步方法,因为同步会导致效率的降低,应尽可能使少的代码进行同步
④ 加锁的时候应该保证多个线程的锁对象为同一个
//加锁的时候应该保证多个线程的锁对象为同一个 //如果是使用继承Thread的方式实现多线程,则不能保证锁对象为一个 //因为这种方式实现的多线程,是不同的T对象运行同步代码块,相当于同步代码块中的this是指的不同的对象,也就是一个对象对应着一把锁,不能保证锁对象唯一。 public class main{ public static void main(String[] args){ T t1 = new T(); T t2 = new T(); t1.start(); t2.start(); // 实现接口方式,则可以保证锁对象唯一 T1 tt1 = new T1(); Thread thread1 = new Thread(tt1); Thread thread2 = new Thread(tt1); thread1.start(); thread2.start(); } } class T extends Thread{ synchronized (this){ ... } } class T1 implements Runnable { synchronized (this){ ... } }
死锁:
//案例 package com.edu.threaduse; /** * @author mtl121 * @version 1.0 */ public class DeadLock { public static void main(String[] args) { T4 t1 = new T4(true); T4 t2 = new T4(false); t1.setName("A线程"); t2.setName("B线程"); t1.start(); t2.start(); } } class T4 extends Thread { static Object o1 = new Object(); static Object o2 = new Object(); boolean flag; public T4(boolean flag) { this.flag = flag; } @Override public void run() { if(flag == true){ synchronized (o1){ System.out.println("拿到o1"); try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (o2){ System.out.println("拿到o2"); } } } else{ synchronized (o2){ System.out.println("拿到o2"); try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (o1){ System.out.println("拿到o1"); } } } } }
释放锁的操作:
①当前线程的同步方法和同步代码块执行完毕
②当前线程的同步方法或同步代码块遇到break,return
③当前线程在同步代码块中,同步方法中出现了未处理的Exception或者Error,导致异常结束
④当前线程在同步代码块中,同步方法中执行了线程对象的wait方法,当前线程暂停,释放锁