Callable接口 线程池 死锁 wait和sleep区别

1.Callable接口
该接口和runnable接口差不多,但是有返回值,能够返回run方法运行的结果值。
2.线程池Executor
该类的构造器为:ScheduledThreadPoolExecutor(int corePollSize);传入的值为可运行的最大线程数,如果大于这个值,则多余的线程会进入等待,直至该类中有线程运行结束才能继续进入运行。
主要方法:
(1)submit(); 该方法中可传入Runnable,Callable的实现类,可以有返回值;
(2)shutdown();在程序运行完毕后需要执行此方法,否则程序不会停止。
下面有使用代码列子:

public class Test1_1 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService es = new ScheduledThreadPoolExecutor(1);
        Future<Integer> f = es.submit(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                System.out.println("1开始"+System.currentTimeMillis());
                Thread.sleep(2000);
                System.out.println("1结束"+System.currentTimeMillis());
                return 0;
            }
        });

        Future<Integer> f2= es.submit(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {

                System.out.println("2开始"+System.currentTimeMillis());
                Thread.sleep(2000);
                System.out.println("2结束"+System.currentTimeMillis());
                return 0;
            }
        });
        //这里需要结束es对象,否则程序会一直执行
        es.shutdown();
    }
}

打印:
1开始1586436212133
1结束1586436214134
2开始1586436214134
2结束1586436216134

当设置成1时,只能有一个线程运行。所以上述两个线程在执行开始时间会差2000左右。

2.死锁
死锁需要用到两个及以上的线程,和多把锁,比较简单,代码如下:

public class Test2_1 {
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized ("a"){
                    System.out.println(Thread.currentThread().getName()+"获取到了a");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"正在获取b");
                    synchronized ("b"){
                        System.out.println(Thread.currentThread().getName()+"获取到b");
                    }
                }
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized ("b"){
                    System.out.println(Thread.currentThread().getName()+"获取到了b");
                    System.out.println(Thread.currentThread().getName()+"正在获取a");
                    synchronized ("a"){
                        System.out.println(Thread.currentThread().getName()+"获取到a");
                    }
                }
            }
        }).start();
    }
}

上述代码在打印:
Thread-0获取到了a
Thread-1获取到了b
Thread-1正在获取a
Thread-0正在获取b

后一直运行,因为 a,b两个资源被两个不同的线程线程占用着,并且两个不同的线程又在同时等待着b,a资源。所以产生了死锁。

3.wait和sleep区别
wait是Object中的方法,sleep是Thread类中的方法, wait需要放在锁中,并且wait的时候释放锁对象,也就是其他线程可以访问当前锁的对象,sleep放在锁中不会释放当前锁对象,其他线程不能访问。
题目:
请用“等待唤醒”机制编写一个程序,要求:
第一个线程:遍历1–1000所有的数字,在遍历过程中,如果发现这个数字能同时被
2,3,5,7整除,立即wait()退出等待,让第二个线程进入。
第二个线程:运行后,将一个计数器 + 1,之后再唤醒等待的线程。

代码:

public class Test3_1 {
    //创建一个计数器,初始值为0
    static int count = 0;
    //创建一个obj对象,用来作为锁的对象
    static Object obj = new Object();
    //定义一个boolean变量,用于判断遍历的线程是否结束,这样用于计数的线程就可以根据这个值来判断循环是否结束。
    static volatile boolean isExit = false;

    public static void main(String[] args) throws InterruptedException {
        //定义一个用于计数的线程
        Thread addThread = new Thread(new Runnable() {
            @Override
            public void run() {
                //将obj对象锁住
                synchronized (obj) {
                    //根据isExit的值判断循环是否可以继续进行,若isExit为true 则说明另一个线程已遍历结束,该循环可终止。
                    while (!isExit) {
                        //循环一次count值加一
                        count++;
                        try {
                            //唤醒遍历线程
                            obj.notify();
                            //该线程进入无限等待状态
                            obj.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        });
        //定义一个用于遍历的线程
        Thread traverseThread = new Thread(new Runnable() {
            @Override
            public void run() {
                //将obj对象锁住
                synchronized (obj) {
                    //循环遍历1-1000
                    for (int i = 1; i <= 1000; i++) {
                        //如果当前i的值符合条件,则执行if语句中的内容
                        if (isOk(i)) {
                            try {
                                //唤醒计数线程
                                obj.notify();
                                //当前线程进入无限等待状态
                                obj.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                    //循环结束,将isExit的值设置为true,这样计数线程可以根据这个值将循环结束
                    isExit = true;
                    //唤醒计数线程
                    obj.notify();
                }
            }
        });
        //开始遍历的线程
        traverseThread.start();
        //让主线程睡眠0.1秒,避免计数线程先拿到锁
        Thread.sleep(100);
        //开始计数线程
        addThread.start();
        //等待遍历线程的结束
        traverseThread.join();
        //等待计数线程的结束
        addThread.join();
        //打印count值
        System.out.println(count);

    }

    //自定义方法,用于判断传入值 是否可以同时被2,3,5,7整除
    public static boolean isOk(int x) {
        return x % 2 == 0 && x % 3 == 0 && x % 5 == 0 && x % 7 == 0;
    }
}

打印:
4

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值