22 - 线程安全 死锁 同步锁
1. 同步锁 多个线程想保证线程安全,必须要使用同一个锁对象 同步代码块 synchronized (锁对象){ 可能产生线程安全问题的代码 } 同步代码块的锁对象可以是任意的对象 同步方法 public synchronized void method() 可能产生线程安全问题的代码 } 同步方法中的锁对象是 this 静态同步方法 public synchronized void method() 可能产生线程安全问题的代码 } 静态同步方法中的锁对象是 类名.class 2. 多线程有几种实现方案,分别是哪几种? a, 继承Thread类 b, 实现Runnable接口 c, 通过线程池,实现Callable接口 3. 同步有几种方式,分别是什么? a,同步代码块 b,同步方法 静态同步方法 4. 启动一个线程是run()还是start()?它们的区别? 启动一个线程是start() 区别: start: 启动线程,并调用线程中的run()方法 run : 执行该线程对象要执行的任务 5. sleep()和wait()方法的区别 sleep: 不释放锁对象, 释放CPU使用权 在休眠的时间内,不能唤醒 wait(): 释放锁对象, 释放CPU使用权 在等待的时间内,能唤醒 6. 为什么wait(),notify(),notifyAll()等方法都定义在Object类中 锁对象可以是任意类型的对象
package cn.itcast.demo; /* * 通过线程休眠,出现安全问题 * 解决安全问题,Java程序,提供技术,同步技术 * 公式: * synchronized(任意对象){ * 线程要操作的共享数据 * } * 同步代码块 */ public class Tickets implements Runnable{ //定义出售的票源 private int ticket = 100; private Object obj = new Object(); public void run(){ while(true){ //线程共享数据,保证安全,加入同步代码块 synchronized(obj){ //对票数判断,大于0,可以出售,变量--操作 if( ticket > 0){ try{ Thread.sleep(10); }catch(Exception ex){} System.out.println(Thread.currentThread().getName()+" 出售第 "+ticket--); } } } } }
package cn.itcast.demo; /* * 多线程并发访问同一个数据资源 * 3个线程,对一个票资源,出售 */ public class ThreadDemo { public static void main(String[] args) { //创建Runnable接口实现类对象 Tickets t = new Tickets(); //创建3个Thread类对象,传递Runnable接口实现类 Thread t0 = new Thread(t); Thread t1 = new Thread(t); Thread t2 = new Thread(t); t0.start();t1.start();t2.start(); } }
-----
package cn.itcast.demo1; /* * 采用同步方法形式,解决线程的安全问题 * 好处: 代码简洁 * 将线程共享数据,和同步,抽取到一个方法中 * 在方法的声明上,加入同步关键字 * * 问题: * 同步方法有锁吗,肯定有,同步方法中的对象锁,是本类对象引用 this * 如果方法是静态的呢,同步有锁吗,绝对不是this * 锁是本类自己.class 属性 * 静态方法,同步锁,是本类类名.class属性 */ public class Tickets implements Runnable{ //定义出售的票源 private int ticket = 100; public void run(){ while(true){ payTicket(); } } public synchronized void payTicket(){ if( ticket > 0){ try{ Thread.sleep(10); }catch(Exception ex){} System.out.println(Thread.currentThread().getName()+" 出售第 "+ticket--); } } }
package cn.itcast.demo1; /* * 多线程并发访问同一个数据资源 * 3个线程,对一个票资源,出售 */ public class ThreadDemo { public static void main(String[] args) { //创建Runnable接口实现类对象 Tickets t = new Tickets(); //创建3个Thread类对象,传递Runnable接口实现类 Thread t0 = new Thread(t); Thread t1 = new Thread(t); Thread t2 = new Thread(t); t0.start();t1.start();t2.start(); } }
----
package cn.itcast.demo2; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /* * 使用JDK1.5 的接口Lock,替换同步代码块,实现线程的安全性 * Lock接口方法: * lock() 获取锁 * unlock()释放锁 * 实现类ReentrantLock */ public class Tickets implements Runnable{ //定义出售的票源 private int ticket = 100; //在类的成员位置,创建Lock接口的实现类对象 private Lock lock = new ReentrantLock(); public void run(){ while(true){ //调用Lock接口方法lock获取锁 lock.lock(); //对票数判断,大于0,可以出售,变量--操作 if( ticket > 0){ try{ Thread.sleep(10); System.out.println(Thread.currentThread().getName()+" 出售第 "+ticket--); }catch(Exception ex){ }finally{ //释放锁,调用Lock接口方法unlock lock.unlock(); } } } } }
package cn.itcast.demo2; /* * 多线程并发访问同一个数据资源 * 3个线程,对一个票资源,出售 */ public class ThreadDemo { public static void main(String[] args) { //创建Runnable接口实现类对象 Tickets t = new Tickets(); //创建3个Thread类对象,传递Runnable接口实现类 Thread t0 = new Thread(t); Thread t1 = new Thread(t); Thread t2 = new Thread(t); t0.start();t1.start();t2.start(); } }
===
package cn.itcast.demo3; public class LockA { private LockA(){} public static final LockA locka = new LockA(); }
package cn.itcast.demo3; public class LockB { private LockB(){} public static final LockB lockb = new LockB(); }
package cn.itcast.demo3; public class DeadLockDemo { public static void main(String[] args) { DeadLock dead = new DeadLock(); Thread t0 = new Thread(dead); Thread t1 = new Thread(dead); t0.start(); t1.start(); } }
package cn.itcast.demo3; public class DeadLock implements Runnable{ private int i = 0; public void run(){ while(true){ if(i%2==0){ //先进入A同步,再进入B同步 synchronized(LockA.locka){ System.out.println("if...locka"); synchronized(LockB.lockb){ System.out.println("if...lockb"); } } }else{ //先进入B同步,再进入A同步 synchronized(LockB.lockb){ System.out.println("else...lockb"); synchronized(LockA.locka){ System.out.println("else...locka"); } } } i++; } } }
====
package cn.itcast.demo4; /* * 开启输入线程和输出线程,实现赋值和打印值 */ public class ThreadDemo{ public static void main(String[] args) { Resource r = new Resource(); Input in = new Input(r); Output out = new Output(r); Thread tin = new Thread(in); Thread tout = new Thread(out); tin.start(); tout.start(); } }
package cn.itcast.demo4; /* * 定义资源类,有2个成员变量 * name,sex * 同时有2个线程,对资源中的变量操作 * 1个对name,age赋值 * 2个对name,age做变量的输出打印 */ public class Resource { public String name; public String sex; public boolean flag = false; }
package cn.itcast.demo4; /* * 输出线程,对资源对象Resource中成员变量,输出值 */ public class Output implements Runnable { private Resource r ; public Output(Resource r){ this.r = r; } public void run() { while(true){ synchronized(r){ //判断标记,是false,等待 if(!r.flag){ try{r.wait();}catch(Exception ex){} } System.out.println(r.name+".."+r.sex); //标记改成false,唤醒对方线程 r.flag = false; r.notify(); } } } }
package cn.itcast.demo4; /* * 输入的线程,对资源对象Resource中成员变量赋值 * 一次赋值 张三,男 * 下一次赋值 lisi,nv */ public class Input implements Runnable { private Resource r ; public Input(Resource r){ this.r = r; } public void run() { int i = 0 ; while(true){ synchronized(r){ //标记是true,等待 if(r.flag){ try{r.wait();}catch(Exception ex){} } if(i%2==0){ r.name = "张三"; r.sex = "男"; }else{ r.name = "lisi"; r.sex = "nv"; } //将对方线程唤醒,标记改为true r.flag = true; r.notify(); } i++; } } }