1、死锁

  (1)同步锁使用的弊端:当线程任务中出现了多个同步(多个锁)时,如果同步中嵌套了其他的同步。这时容易引发一种现象:程序出现无限等待,这种现象我们称为死锁。这种情况能避免就避免掉;

synchronzied(A锁){
synchronized(B锁){ }
}

  (2)代码演示

    ①定义锁对象

 public class MyLock {
public static final Object lockA = new Object();
public static final Object lockB = new Object();
}

    ②线程任务类

 import java.util.Random;

 public class ThreadTask implements Runnable {
int x = new Random().nextInt(1);// 0,1 // 指定线程要执行的任务代码
@Override
public void run() {
while (true) {
if (x % 2 == 0) {
// 情况一
synchronized (MyLock.lockA) {
System.out.println("if-LockA");
synchronized (MyLock.lockB) {
System.out.println("if-LockB");
System.out.println("if大口吃肉");
}
}
} else {
// 情况二
synchronized (MyLock.lockB) {
System.out.println("else-LockB");
synchronized (MyLock.lockA) {
System.out.println("else-LockA");
System.out.println("else大口吃肉");
}
}
}
x++;
}
}
}

    ③测试类

 public class ThreadDemo {
public static void main(String[] args) {
// 创建线程任务类对象
ThreadTask task = new ThreadTask();
// 创建两个线程
Thread t1 = new Thread(task);
Thread t2 = new Thread(task);
// 启动线程
t1.start();
t2.start();
}
}

2、Lock接口

  (1)Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作;

  (2)Lock提供了一个更加面对对象的锁,在该锁中提供了更多的操作锁的功能;

  (3)我们使用Lock接口,以及其中的lock()方法和unlock()方法替代同步,对卖票案例中Ticket类进行如下代码修改:

 public class Ticket implements Runnable {
//共100票
int ticket = 100; //创建Lock锁对象
Lock ck = new ReentrantLock(); @Override
public void run() {
//模拟卖票
while(true){
//synchronized (lock){
ck.lock();
if (ticket > 0) {
//模拟选坐的操作
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在卖票:" + ticket--);
}
ck.unlock();
//}
}
}
}

3、等待唤醒机制

  (1)线程之间的通信:多个线程在处理同一个资源,但是处理的动作(线程的任务)却不相同;

  (2)通过一定的手段使各个线程能有效的利用资源。而这种手段即—— 等待唤醒机制;

  (3)等待唤醒机制所涉及到的方法:

    ①wait() :等待,将正在执行的线程释放其执行资格 和 执行权,并存储到线程池中;

    ②notify():唤醒,唤醒线程池中被wait()的线程,一次唤醒一个,而且是任意的;

    ③notifyAll(): 唤醒全部:可以将线程池中的所有wait() 线程都唤醒。

  (4)其实,所谓唤醒的意思就是让线程池中的线程具备执行资格;

  (5)这些方法都是在同步中才有效,同时这些方法在使用时必须标明所属锁,这样才可以明确出这些方法操作的到底是哪个锁上的线程;

  (6)仔细查看JavaAPI之后,发现这些方法 并不定义在 Thread中,也没定义在Runnable接口中,却被定义在了Object类中,为什么这些操作线程的方法定义在Object类中?

  因为这些方法在使用时,必须要标明所属的锁,而锁又可以是任意对象。能被任意对象调用的方法一定定义在Object类中;

  (7)模拟等待唤醒机制的实现,代码案例:

    ①模拟资源类

 public class Resource {
private String name;
private String sex;
private boolean flag = false; public synchronized void set(String name, String sex) {
if (flag)
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
// 设置成员变量
this.name = name;
this.sex = sex;
// 设置之后,Resource中有值,将标记该为 true ,
flag = true;
// 唤醒output
this.notify();
} public synchronized void out() {
if (!flag)
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
// 输出线程将数据输出
System.out.println("姓名: " + name + ",性别: " + sex);
// 改变标记,以便输入线程输入数据
flag = false;
// 唤醒input,进行数据输入
this.notify();
}
}

    ②输入线程人任务类

 public class Input implements Runnable {
private Resource r; public Input(Resource r) {
this.r = r;
} @Override
public void run() {
int count = 0;
while (true) {
if (count == 0) {
r.set("小明", "男生");
} else {
r.set("小花", "女生");
}
// 在两个数据之间进行切换
count = (count + 1) % 2;
}
}
}

    ③输出线程任务类

 public class Output implements Runnable {
private Resource r; public Output(Resource r) {
this.r = r;
} @Override
public void run() {
while (true) {
r.out();
}
}
}

    ④测试类

 public class ResourceDemo {
public static void main(String[] args) {
// 资源对象
Resource r = new Resource();
// 任务对象
Input in = new Input(r);
Output out = new Output(r);
// 线程对象
Thread t1 = new Thread(in);
Thread t2 = new Thread(out);
// 开启线程
t1.start();
t2.start();
}
}

最新文章

  1. html之长文本框置顶
  2. python取文件最后几行
  3. swift 多线程及GCD
  4. Android 学习之路
  5. Unit06 - 抽象类、接口和内部类(下) 、 面向对象汇总
  6. OpenSSL命令---pkcs7
  7. C/C++ 位域
  8. [转载] 为 Key-Value 数据库实现 MVCC 事务
  9. OC基础17:归档
  10. 201521123036 《Java程序设计》第7周学习总结
  11. Https系列之四:https的SSL证书在Android端基于okhttp,Retrofit的使用
  12. 【转】npm包管理器那些事
  13. 学号:201621123032 《Java程序设计》第2周学习总结
  14. HTTP协议及其相关
  15. [UE4]Grab抓取
  16. Codeforces340 E. Iahub and Permutations
  17. python自带线程池
  18. winform里直接使用WCF,不需要单独的WCF项目
  19. 【注册码】Matlab7.0(R14)注册码
  20. 洛谷 P3302 [SDOI2013]森林

热门文章

  1. Vue常见面试题汇总
  2. obdg反汇编破解crackme
  3. 【RHEL7/CentOS7服务控制之systemctl命令】
  4. gitlab-ce-11.0.1 安装及汉化
  5. CodeForcesGym 100502G Outing
  6. HttpComponents入门解析
  7. Springboot分布式限流实践
  8. js---05 自定义属性
  9. Kinect 开发 —— ColorBasic
  10. C/C++(语句,数组)