Java多线程02

目录

1.死锁以及如何避免死锁

 2.线程通信

3.线程的状态

4. 线程池

4.1 如何创建线程池

4.1.1固定长度线程池

4.1.2单一线程池

 4.1.3可变线程池

4.1.4延迟线程池

4.2原生模式创建线程池

5. 补充(实现Callable接口创建线程 )


1.死锁以及如何避免死锁

①死锁

  • 当线程A持有独占锁a,并尝试去获取独占锁b的同时,线程B持有独占锁b,并尝试获取独占锁a的情况下,就会发生AB两个线程由于互相持有对方需要的锁,而发生的阻塞现象,称之为死锁。
  • 一个线程可以同时拥有多个对象的锁标记,当线程阻塞时,不会释放已经拥有的锁标记,因此可能会造成死锁

②如何避免死锁

  • 尽量使用tryLock(long timeout, TimeUnit unit)的方法(ReentrantLock, ReentrantReadWriteLock),设置超时时间,超时可以退出防止死锁。
  • 尽量使用Java.util.concurrent下的并发类 代替自己手写锁。
  • 尽量降低锁的使用力度,尽量不要几个功能用同一把锁。
  • 尽量减少同步的代码块的嵌套。
public class BoyTask extends Thread{
    @Override
    public void run() {
        synchronized (LockObject.lockA){
            System.out.println("男孩获得画板");
            synchronized (LockObject.lockB){
                System.out.println("男孩获得画笔");
                System.out.println("男孩可以画画了");
            }
        }
    }
}

public class GirlTask extends Thread{
    @Override
    public void run() {
        synchronized (LockObject.lockB){
            System.out.println("女孩获得画笔");
            synchronized (LockObject.lockA){
                System.out.println("女孩获得画板");
                System.out.println("女孩可以画画了");
            }
        }
    }
}

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

public class Test07 {
    public static void main(String[] args) {
        BoyTask boyTask = new BoyTask();
        GirlTask girlTask = new GirlTask();
        boyTask.start();
        girlTask.start();
    }
}

 2.线程通信

sleep()wait()的区别:

  • 来自不同的类:wait来自于Object类中,sleep来自Thread中。
  • 作用位置不同:wait必须放在同步代码块中,而sleep可以放在任意位置。
  • 是否会释放锁资源:wait会释放锁资源,sleep不会释放锁资源。
  • 用法:wait需要notify或notifyAll唤醒,而sleep到时间自动唤醒。

notify()notifyAll()的区别:

  • notify随机唤醒等待对队列中的一个线程,notifyAll会唤醒等待队列中的所有线程。
  • notifyAll()调用后,会将全部想成由等待池移到锁池,然后参与锁的竞争,竞争成功后则继续执行,如果不成功则留在锁池中等待被释放后再次参与竞争。而notify()只会唤醒一个线程,具体唤醒哪一个线程一虚拟机控制。

public class BankCard {
    private int balance;
    //当flag为true时表示卡中有钱,为false时表示卡中没钱
    private boolean flag;
    //存钱
    public synchronized void save(int money){
        if (flag){
            try {
                wait();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        balance+=money;
        System.out.println(Thread.currentThread().getName()+"往卡中存了"+money+"元,卡中剩余"+balance+"元");
        flag=true;
        notify();

    }
    //取钱
    public synchronized void take(int money){
        if(flag==false){
            try {
                wait();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        balance-=money;
        System.out.println(Thread.currentThread().getName()+"从卡中取了"+money+"元,卡中剩余"+balance+"元");
        flag=false;
        notify();
    }
}

public class BankCard {
    private int balance;
    //当flag为true时表示卡中有钱,为false时表示卡中没钱
    private boolean flag;
    //存钱
    public synchronized void save(int money){
        if (flag){
            try {
                wait();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        balance+=money;
        System.out.println(Thread.currentThread().getName()+"往卡中存了"+money+"元,卡中剩余"+balance+"元");
        flag=true;
        notify();

    }
    //取钱
    public synchronized void take(int money){
        if(flag==false){
            try {
                wait();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        balance-=money;
        System.out.println(Thread.currentThread().getName()+"从卡中取了"+money+"元,卡中剩余"+balance+"元");
        flag=false;
        notify();
    }
}


public class SaveTask implements Runnable{
    private BankCard bankCard;
    public SaveTask(BankCard bc){
        bankCard=bc;
    }
    @Override
    public void run() {
        for (int i = 0; i <5; i++) {
            bankCard.save(798);
        }
    }
}


public class TakeTask implements Runnable{
    private BankCard bankCard;
    public TakeTask(BankCard bc){
        bankCard=bc;
    }
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            bankCard.take(798);
        }
    }
}


public class Test08 {
    public static void main(String[] args) {
        BankCard bankCard = new BankCard();
        SaveTask saveTask = new SaveTask(bankCard);
        TakeTask takeTask = new TakeTask(bankCard);
        Thread t1 = new Thread(saveTask,"father");
        Thread t2 = new Thread(takeTask,"son");
        t1.start();
        t2.start();
    }
}

3.线程的状态

  1. 新建(New):当线程对象被创建但尚未启动时处于新建状态。

  2. 可运行/就绪(Runnable)线程对象调用了status()方法后,线程处于可运行状态。在可运行状态下,线程可能正在执行,也可能正在等待系统资源(如处理器时间片)。

  3. 运行(Running)线程获得了处理器时间片正在执行其任务

  4. 阻塞(Blocked)线程被阻塞并暂时停止执行,通常是因为等待某个操作的完成(如等待I/O操作、等待获取锁、等待某个条件满足等)。

  5. 等待(Waiting)线程等待某个特定条件的发生,需要其他线程显式地唤醒(如通过wait()方法)。

  6. 超时等待(Timed Waiting)线程等待一段特定时间,超过时间后会自动唤醒

  7. 终止(Terminated)线程执行完毕或出现异常导致终止,不再可运行

4. 线程池

4.1 如何创建线程池

(1)线程池的种类:

  • 固定长度的线程池

  • 单一线程池

  • 可变线程池

  • 延迟线程池

(2)线程池中参数的意思:

  • core: 核心线程数
  • max: 最大线程池数
  • long: 等待时长
  • unit: 等待单位
  • BlockQueue:等待队列对象。

(3)Executor: 它是线程池的根接口:

  • void execute(Runnable command):执行Runnable类型的任务。

 (4) ExecutorService: Executor的子接口。

  • void shutdown():关闭线程池。需要等任务执行完毕。
  • shutdownNow(); 立即关闭线程池。 不会再接受新的任务。
  • isShutdown(): 判断是否执行了关闭。
  • isTerminated(): 判断线程池是否终止。表示线程池中的任务都执行完毕,线程池关闭。
  • submit(Callable<T> task);提交任务,可以提交Callable。
  • submit(Runnable task): 提交任务,可以提交Runnable。

  (5)Executors: 线程池的工具类,该类提供了创建线程池的一些静态方法。

以下是通过通过Executors工具类创建线程池: 

4.1.1固定长度线程池

public class Test09 {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        for (int i = 0; i < 20; i++) {
            executorService.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName()+"~~~~~~~~~~~");
                }
            });
        }
        executorService.shutdown();
//        executorService.shutdownNow();
    }
}

4.1.2单一线程池

class Test10{
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 5; i++) {
            executorService.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName()+"~~~~~~~~~~~");
                }
            });
        }
    }
}

 4.1.3可变线程池

class Test11{
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        for (int i = 0; i < 20; i++) {
            executorService.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName()+"~~~~~~~~~~~");
                }
            });
        }
        executorService.shutdown();
    }
}

4.1.4延迟线程池

class Test12{
    public static void main(String[] args) {
        ScheduledExecutorService executorService = Executors.newScheduledThreadPool(10);
        for (int i = 0; i < 10; i++) {
            executorService.schedule(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName()+"~~~~~~~~~~~");
                }
            },5,TimeUnit.SECONDS);
        }
        executorService.shutdown();
    }
}

4.2原生模式创建线程池

class Test13{
    public static void main(String[] args) {
        //capacity:5  最多有五个任务在等待
        BlockingQueue<Runnable> workQueye=new ArrayBlockingQueue<>(5);
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10, 5, TimeUnit.SECONDS, workQueye);
        for (int i = 0; i < 20; i++) {
            threadPoolExecutor.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName()+"~~~~~~~~~~~~~");
                }
            });
        }
    }
}

5. 补充(实现Callable接口创建线程 )

public class Test {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //①创建线程对象
        MyCallable myCallable = new MyCallable();
        //把线程任务封装到FuntureTask类中,该类可以获取线程任务执行后的结果.
        FutureTask<Integer> integerFutureTask = new FutureTask<>(myCallable);
        Thread thread = new Thread(integerFutureTask);
        thread.start();
        System.out.println(integerFutureTask.get());

        //②使用线程池来执行任务
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        Future<Integer> submit = executorService.submit(new MyCallable());
        System.out.println(submit.get());
        executorService.shutdown();
    }
}

public class MyCallable implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        int sum=0;
        for (int i = 0; i < 100; i++) {
            sum+=i;
        }
        return sum;
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值