Java基础二十八(线程练习与补充)

线程通信的例子:使用两个线程打印1-100.线程一、线程二交替打印

  • 涉及到的三个方法:
      wait():一旦执行此方法,当前线程就进入阻塞状态,并释放同步监视器
      notify():一旦执行此方法,就会唤醒被wait的一个线程。如果有多个线程被wait,就唤醒优先级高的wait
      notifyAll():一旦执行此方法,就会唤醒被wait的所有线程
  • 注意:
      1.上述三个方法只能使用在同步代码块或者同步方法中
      2.上述方法的调用者必须是同步代码块或同步方法中的同步监视器,否则出现IllegalMonitorStateException异常
      3.三种方都是定义在Object类中
  • 面试题:sleep()和wait()的异同?
      1.相同点:一旦执行方法,都可以使得当前的线程进入阻塞状态
      2.不同点:
        ①两个方法声明的位置不同:Thread类中声明sleep(),Object类中声明wait()
        ②调用方法不同:sleep()可以在任何需要的场景下使用,wait()必须使用在同
        ③关于是否释放同步监视器:如果两个方法都是在用在同步代码块或同步方法中,sleep()不会释放同步监视器,wait()会释放同步监视器(锁)
class Number implements Runnable{

    private int number = 1;
    private Object obj = new Object();
    //任何一个类的对象都像(唯一)

    @Override
    public void run() {
        while (true) {
//            synchronized (this) {
            synchronized (obj) {
                //唤醒
//                this.notify();
                obj.notify();
                if (number <= 100) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + ":" + number);
                    number++;
                    try {
                        //使得调用如下wait()方法的线程进入阻塞状态
//                        this.wait();
                        obj.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } else {
                    break;
                }
            }
        }
    }


}

public class CommunicationTest {
    public static void main(String[] args) {
        Number number = new Number();
        Thread t1 = new Thread(number);
        Thread t2 = new Thread(number);

        t1.setName("线程一");
        t2.setName("线程二");

        t1.start();
        t2.start();
    }
}

线程通信的应用:经典问题:生产者/消费者问题

  • 生产者(Productor)将产品交给店员(Clerk),而消费者(Customer)从店员处取走产品,店员一次只能持有固定数量的产品(比如:20)。如果生产者试图生产更多的产品,店员会叫生产者停一下,如果店中有空位放产品了再通知生产者继续生产;如果店中没有产品了,店员会叫消费者等一下,如果店中有产品了再通知消费者来取走产品。

  • 分析:
      1.多线程问题:生产者线程,消费者线程
      2.存在共享数据:店员(或产品)
      3.同步机制解决线程安全问题
      4.涉及线程的通信

class Clerk{

    private int productCount = 0;

    //生产产品
    public synchronized void produceProduct() {
        if (productCount < 20){
            productCount++;
            System.out.println(Thread.currentThread().getName() + ":开始生产第" + productCount + "几个产品");
            notify();
        }else {
            //等待
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    //消费产品
    public synchronized void consumerProduct() {
        if(productCount > 0){
            System.out.println(Thread.currentThread().getName() + "开始消费第" + productCount + "个产品");
            productCount--;
            notify();
        }else {
            //等待
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class Producer extends Thread{//生产者

    private Clerk clerk;
    public Producer(Clerk clerk){
        this.clerk = clerk;
    }

    @Override
    public void run() {
        System.out.println(getName() + "开始生产产品");
        while (true){
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            clerk.produceProduct();
        }
    }
}

class Consumer extends Thread{//消费者

    private Clerk clerk;
    public Consumer(Clerk clerk){
        this.clerk = clerk;
    }

    @Override
    public void run() {
        System.out.println(getName() + "开始消费产品");
        while (true){
            try {
                Thread.sleep(20);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            clerk.consumerProduct();
        }
    }
}
public class ProductTest {
    public static void main(String[] args) {
        Clerk clerk = new Clerk();

        Producer p1 = new Producer(clerk);
        p1.setName("生产者1");

        Consumer c1 = new Consumer(clerk);
        c1.setName("消费者1");

        Consumer c2 = new Consumer(clerk);
        c2.setName("消费者2");

        p1.start();
        c1.start();
        c2.start();
    }
}

创建线程的方式三:实现Callable接口 -->jdk5.0新增

  • 如何理解Callable接口的方式创建多此线程比Runnable接口的方式更强大
      1.call()有放回值
      2.call()可以抛出异常,被外围操作捕获,获取异常的信息
      3.callable支持泛型
//创建一个实Callable的实现类
class NumThread implements Callable{

    //实现call方法,将此线程需要执行的操作声明在call()中
    @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;
        //return null;
    }
}
public class ThreadNew {
    public static void main(String[] args) {
        //3.创建Callable接口实现类的对象
        NumThread numThread = new NumThread();
        //4.将此Callable接口实现类的对象作为传递值到FutureTask构造器中,创建FutureTask对象
        FutureTask futureTask = new FutureTask(numThread);
        //5。将FutureTask的对象作为参数传递到Thread类的构造器中,创建Thread对象
        Thread t1 = new Thread(futureTask);
        //6.调用start方法
        t1.start();

        try {
            //6.获取Callable中call方法的返回值
            //get方法返回值即为FutureTask构造器参数Callable实现类重写的call()返回值
            Object sum = futureTask.get();
            System.out.println("总和为:" + sum);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

创建线程的方式四:使用线程池*

  • 好处:
      1.提高响应速度
      2.降低资源消耗
      3.便于线程管理
        setCorePoolSize();
        setKeepAliveTime();
class NumberThread implements Runnable{

    @Override
    public void run() {
        for(int i = 0; i <= 100; i++) {
            if (i % 2 == 0) {
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
        }
    }
}

class NumberThread1 implements Runnable{

    @Override
    public void run() {
        for(int i = 0; i <= 100; i++) {
            if (i % 2 != 0) {
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
        }
    }
}
public class ThreadPool {
    public static void main(String[] args) {
        //1.提供指定线程数量的线程池
        ExecutorService service = Executors.newFixedThreadPool(10);

        //设置线程池的属性
//        System.out.println(service.getClass());//class java.util.concurrent.ThreadPoolExecutor
//        ThreadPoolExecutor service1 = (ThreadPoolExecutor) service;
//        service1.setCorePoolSize(15);
//        service1.setKeepAliveTime();


        //2.执行指定的线程的操作,需要提供实现Runnable接口或Callable接口实现类的对象
        service.execute(new NumberThread());//适合用于Runnable
        service.execute(new NumberThread1());
//        service.submit();//适合用于Callable
        //3.关闭连接池
        service.shutdown();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值