Java学习13 死锁 锁 线程协作与线程池

死锁

  • 多个线程各自占有一些共享资源 并且相互等待其他线程占有的资源才能运行 而导致两个或者多个线程都在等待对方释放资源 都停止执行的情形 某一个同步块同时拥有两个以上对象的锁时,就有可能发生"死锁"问题
  • 产生死锁的四个必要条件:
    1. 互斥条件:一个资源每次只能被一个进程使用
    2. 请求于保持条件:一个进程因请求资源而阻塞时, 对已获得的资源保持不放
    3. 不剥削条件: 进程已获得的资源 在未使用完之前 不能强行剥夺
    4. 循环等待条件: 若干进程之间形成一种头尾相接的循环等待资源关系
package com.wu.thread;

public class Demo20 {
    public static void main(String[] args) {
        new MakeUp(0,"小红").start();
        new MakeUp(1,"小敏").start();
    }
}

class  Lipstick{}
class  Mirror{}
class  MakeUp extends Thread{
   static  Lipstick lipstick = new Lipstick();
   static  Mirror mirror = new Mirror();

    int choice;
    String girlName;
    public  MakeUp(int choice, String girlName){
        this.choice = choice;
        this.girlName = girlName;
    }

    @Override
    public void run() {
        makeUp();
    }

    private void makeUp(){
        if(choice ==0){
            synchronized (lipstick){
                System.out.println(this.girlName + "用口红");
                synchronized (mirror){
                    System.out.println(this.girlName + "用镜子");
                }
            }
        }else {
            synchronized (mirror){
                System.out.println(this.girlName+ "用镜子");
                synchronized (lipstick){
                    System.out.println(this.girlName + "用口红");
                }
            }
        }
    }
}

Lock(锁)

  • 从JDK5.0开始 Java提供更强大的线程同步机制 通过显示定义同步锁对象来实现同步 同步锁使用Lock对象充当
  • Lock接口是控制多个线程对共享资源进行访问的工具 锁提供了对共享资源的独占访问 每次只能有一个线程对Lock对象加锁 线程开始访问共享资源之间应先获得Lock对象
  • ReentrantLock类实现类Lock
 private final ReentrantLock lock = new ReentrantLock();
try{
   lock.lock();
    ...
}finally{
    lock.unlock();
}

线程协作

  • 生产者消费模式

  • 线程通信方法

    1. wait() 表示线程一直等待 直到其他线程通知 与sleep 不同 会释放锁
    2. wait(long timeout)指定等待毫秒数
    3. notify() 唤醒一个处于等待状态的线程
    4. notifyAll() 唤醒同一个对象上所有调用wait()方法的线程 优先级别高的线程优先调度
  • 都是Object类的方法 都只能在同步方法或者异步代码块中使用 否则会抛出异常lllegalMonitorStateException

package com.wu.thread;

public class Demo24 {
    public static void main(String[] args) {
        Tv tv = new Tv();
        new Player(tv).start();
        new Audence(tv).start();

    }
}

//演员
class  Player extends  Thread{
    Tv tv;
    public Player(Tv tv){
        this.tv= tv;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            if(i%2 ==0){
                this.tv.show("还珠格格");
            }else {
                this.tv.show("西游记");
            }
        }
    }
}

//观众
class  Audence extends  Thread{
    Tv tv;
    public Audence(Tv tv){
        this.tv=tv;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
           this.tv.watch();
        }
    }
}

//节目
class  Tv {
   String shower;
    boolean flag = true;

    public synchronized void show(String shower){
        if(! flag){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("演员表演了:" + shower);
        this.shower= shower;
        this.notifyAll();
        this.flag = !this.flag;

    }

    public  synchronized   void  watch(){
        if(flag){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("观众观看了:" + shower);
        this.notifyAll();
        this.flag = !this.flag;
    }
}


使用线程池

  • 提前创建好多个线程 放入线程池中 使用时直接获取 使用完放回池中 可以避免频繁创建销毁 实现重复利用. 类似公共交通工具

  • 好处:

    1. 提高响应速度
    2. 降低资源消耗
    3. 便于线程管理
  • ExecutorService :真正的线程池接口 常见子类ThreadPoolExecutor

    1. void execute(Runnable command):执行任务/命令 没有返回值 一般用来执行Runnable
    2. submit(Callable):执行任务 有返回值 一般用来执行Callable
    3. void shutdown() :关闭连接池
  • Executors:工具类 线程池的工厂类 用于创建并返回不同类型的线程池

package com.wu.thread;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Demo26 {
    public static void main(String[] args) {
        //创建线程池服务
        ExecutorService service = Executors.newFixedThreadPool(10);
        //开启服务
        service.execute(new TestThread());
        service.execute(new TestThread());
        service.execute(new TestThread());

        //关闭服务
        service.shutdown();
    }

}

class TestThread implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值