1 多线程的三种加锁方式
/*
* A:同步代码块的锁对象是谁呢?
* 任意对象。
*
* B:同步方法的格式及锁对象问题?
private synchronized void sellTicket() { if (tickets > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "正在出售第" + (tickets--) + "张票 "); } }
while (true) { if(x%2==0){ synchronized (this) { if (tickets > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "正在出售第" + (tickets--) + "张票 "); } } }else { System.out.println(Thread.currentThread().getName() // + "正在出售第" + (tickets--) + "张票 "); sellTicket(); } x++; } }
* 把同步关键字加在方法上。
*
* 同步方法是谁呢?
* this
*
* C:静态方法及锁对象问题?
* 静态方法的锁对象是谁呢?
* 类的字节码文件对象。(反射会讲)
private static synchronized void sellTicket() { if (tickets > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "正在出售第" + (tickets--) + "张票 "); } } }
@Override public void run() { while (true) { if(x%2==0){ synchronized (SellTicket.class) { if (tickets > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "正在出售第" + (tickets--) + "张票 "); } } }else { sellTicket(); } x++; } }
2 死锁的条件
举一个例子,一个老外和一个中国人去吃饭,给老外的餐具是一只筷子和一把刀,给中国人的餐具是一只筷子和一把叉子,但是两个人都在等待对方吃完,在吃自己的食物,
扫描二维码关注公众号,回复:
418793 查看本文章
其实就是 两个或两个以上的线程在争夺资源的过程中,发生的一种相互等待的现象。
死锁的代码举例
public class DieLock extends Thread { private boolean flag; public DieLock(boolean flag) { this.flag = flag; } @Override public void run() { if (flag) { synchronized (MyLock.objA) { System.out.println("if objA"); synchronized (MyLock.objB) { System.out.println("if objB"); } } } else { synchronized (MyLock.objB) { System.out.println("else objB"); synchronized (MyLock.objA) { System.out.println("else objA"); } } } } }
public class DieLockDemo { public static void main(String[] args) { DieLock dl1 = new DieLock(true); DieLock dl2 = new DieLock(false); dl1.start(); dl2.start(); } }
public class MyLock { // 创建两把锁对象 public static final Object objA = new Object(); public static final Object objB = new Object(); }
通过控制台我们可以知道,此时编辑器还是运行的,但是发生了死锁,也就是刚运行完了红色的代码,就被另一个线程dl2给抢走了,然后dl2往下运行 ,运行完粉色的代码,发现此时被 另一个给锁上了,返回dl1,但是此时dl1下面的代码也被锁上了,也就是相互等待了。
3 生产者。消费者的问题概述
那早餐的包子来说,首先是要求老板有包子,顾客才能买,(也就是不能顾客在没有包子的情况下,先买了包子,还有就是顾客在包子买完之后,老板才会继续生产包子)
public class SetThread implements Runnable { private Student s; private int x = 0; public SetThread(Student s) { this.s = s; } @Override public void run() { while (true) { if (x % 2 == 0) { s.set("林青霞", 27); } else { s.set("刘意", 30); } x++; } } }
public class Student { private String name; private int age; private boolean flag; // 默认情况是没有数据,如果是true,说明有数据 public synchronized void set(String name, int age) { // 如果有数据,就等待 if (this.flag) { try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // 设置数据 this.name = name; this.age = age; // 修改标记 this.flag = true; this.notify(); } public synchronized void get() { // 如果没有数据,就等待 if (!this.flag) { try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // 获取数据 System.out.println(this.name + "---" + this.age); // 修改标记 this.flag = false; this.notify(); } }
/* * 分析: * 资源类:Student * 设置学生数据:SetThread(生产者) * 获取学生数据:GetThread(消费者) * 测试类:StudentDemo * * 问题1:按照思路写代码,发现数据每次都是:null---0 * 原因:我们在每个线程中都创建了新的资源,而我们要求的时候设置和获取线程的资源应该是同一个 * 如何实现呢? * 在外界把这个数据创建出来,通过构造方法传递给其他的类。 * * 问题2:为了数据的效果好一些,我加入了循环和判断,给出不同的值,这个时候产生了新的问题 * A:同一个数据出现多次 * B:姓名和年龄不匹配 * 原因: * A:同一个数据出现多次 * CPU的一点点时间片的执行权,就足够你执行很多次。 * B:姓名和年龄不匹配 * 线程运行的随机性 * 线程安全问题: * A:是否是多线程环境 是 * B:是否有共享数据 是 * C:是否有多条语句操作共享数据 是 * 解决方案: * 加锁。 * 注意: * A:不同种类的线程都要加锁。 * B:不同种类的线程加的锁必须是同一把。 * * 问题3:虽然数据安全了,但是呢,一次一大片不好看,我就想依次的一次一个输出。 * 如何实现呢? * 通过Java提供的等待唤醒机制解决。 * * 等待唤醒: * Object类中提供了三个方法: * wait():等待 * notify():唤醒单个线程 * notifyAll():唤醒所有线程 * 为什么这些方法不定义在Thread类中呢? * 这些方法的调用必须通过锁对象调用,而我们刚才使用的锁对象是任意锁对象。 * 所以,这些方法必须定义在Object类中。 * * 最终版代码中: * 把Student的成员变量给私有的了。 * 把设置和获取的操作给封装成了功能,并加了同步。 * 设置或者获取的线程里面只需要调用方法即可。 */ public class StudentDemo { public static void main(String[] args) { //创建资源 Student s = new Student(); //设置和获取的类 SetThread st = new SetThread(s); GetThread gt = new GetThread(s); //线程类 Thread t1 = new Thread(st); Thread t2 = new Thread(gt); //启动线程 t1.start(); t2.start(); } }
public class GetThread implements Runnable { private Student s; public GetThread(Student s) { this.s = s; } @Override public void run() { while (true) { s.get(); } } }