多线程之二

2022/4/3 6:21:22

本文主要是介绍多线程之二,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

线程通信

/**
 * 两个线程交替打印1-100之间的数字
 */
public class ThreadTest3 {
    public static void main(String[] args) {
        Demo04 demo04 = new Demo04();
        Thread t1 = new Thread(demo04);
        Thread t2 = new Thread(demo04);
        t1.setName("线程一");
        t2.setName("线程二");
        t1.start();
        t2.start();
    }
}
class Demo04 implements Runnable{
    private static int i=1;
    @Override
    public void run() {
        while (true){
            synchronized (this){
                //唤醒所有线程,首次执行时无效果
                notifyAll();
                if (i<=100){
                    System.out.println(Thread.currentThread().getName()+":"+i);
                    i++;
                    try {
                        //使当前线程沉睡。可以被notifyAll()和notify()唤醒
                        wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }else {
                    break;
                }
            }
        }
    }
}

wait() 与 notify() 和 notifyAll()

  • wait():令当前线程挂起并放弃CPU、同步资源并等待,使别的线程可访问并修改共享资源,而当 前线程排队等候其他线程调用notify()或notifyAll()方法唤醒,唤醒后等待重新获得对监视器的所有 权后才能继续执行。
  • notify():唤醒正在排队等待同步资源的线程中优先级最高者结束等待
  • notifyAll ():唤醒正在排队等待资源的所有线程结束等待.

这三个方法只有在synchronized方法或synchronized代码块中才能使用,否则会报
java.lang.IllegalMonitorStateException异常。


面试题:sleep() 和 wait()的异同?

  • 相同点:一旦执行方法,都可以使得当前的线程进入阻塞状态。
  • 不同点:
    • 两个方法声明的位置不同:Thread类中声明sleep() , Object类中声明wait()
    • 调用的要求不同:sleep()可以在任何需要的场景下调用。 wait()必须使用在同步代码块或同步方法中
    • 关于是否释放同步监视器:如果两个方法都使用在同步代码块或同步方法中,sleep()不会释放锁,wait()会释放锁。

JDK5.0新增的线程创建方式

实现Callable接口

  • Callable接口

    • 相比run()方法,可以有返回值

    • 方法可以抛出异常

    • 支持泛型的返回值

    • 需要借助FutureTask类,比如获取返回结果

  • Future接口

    • 可以对具体Runnable、Callable任务的执行结果进行取消、查询是 否完成、获取结果等。
    • FutrueTask是Futrue接口的唯一的实现类
    • FutureTask 同时实现了Runnable, Future接口。它既可以作为Runnable被线程执行,又可以作为Future得到Callable的返回值
public class ThreadTest4 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Demo05 demo05 = new Demo05();
        FutureTask futureTask = new FutureTask(demo05);
        new Thread(futureTask).start();
        Object o = futureTask.get();
        System.out.println(o);
    }
}

class Demo05 implements Callable{
    @Override
    public Object call() throws Exception {
        int sum =0;
        for (int i = 1; i <=100 ; i++) {
            if (i%2==0){
                System.out.println(i);
                sum+=i;
            }
        }
        return sum;
    }
}

线程池

  • 背景:经常创建和销毁、使用量特别大的资源,比如并发情况下的线程, 对性能影响很大。
  • 思路:提前创建好多个线程,放入线程池中,使用时直接获取,使用完 放回池中。可以避免频繁创建销毁、实现重复利用。类似生活中的公共交 通工具。

好处

  • 提高响应速度(减少了创建新线程的时间)
  • 降低资源消耗(重复利用线程池中线程,不需要每次都创建)
  • 便于线程管理
    • corePoolSize:核心池的大小
    • maximumPoolSize:最大线程数
    • keepAliveTime:线程没有任务时最多保持多长时间后会终止

实现

  • JDK 5.0起提供了线程池相关API:ExecutorService 和 Executors
  • ExecutorService:真正的线程池接口。常见子类ThreadPoolExecutor
  • Executors:工具类、线程池的工厂类,用于创建并返回不同类型的线程池
public class Pool {
    public static void main(String[] args) {
        ExecutorService service = Executors.newFixedThreadPool(10);
        service.execute(new Demo06());
        service.shutdown();
    }
}
class Demo06 implements Runnable{
    @Override
    public void run() {
        for (int i = 1; i <=100 ; i++) {
            if (i%2==0){
                System.out.println(i);
            }
        }
    }
}



这篇关于多线程之二的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程