经典例题:生产者/消费者问题说明: 生产者(Productor)将产品交给店员(Clerk),而消费者(Customer)从店员处取走产品,店员一次只能持有固定数量的产品(比如:20),如果生产者试图生产更多的产品,店员会叫生产者停一下,如果店中有空位放产品了再通知生产者继续生产;如果店中没有产品了,店员会告诉消费者等一下,如果店中有产品了再通知消费者来取走产品。
分析: 1.是否是多线程问题? 是,生产者线程,消费者线程 2.是否有共享数据? 是,店员(或产品) 3.如何解决线程的安全问题? 同步机制,有三种方法 4.是否涉及线程的通信? 是
public class ProductTest { public static void main(String[] args) { Clerk clerk = new Clerk(); Producer producer = new Producer(clerk); producer.setName("生产者"); Consumer customer = new Consumer(clerk); customer.setName("消费者1"); // Consumer customer1 = new Consumer(clerk); // customer1.setName("消费者2"); producer.start(); customer.start(); // customer1.start(); } } //店员 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(Thread.currentThread().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(Thread.currentThread().getName()+ ":开始消费产品..."); while (true){ try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } clerk.consumerProduct(); } } }创建线程的方式三:实现Callable接口。— JDK 5.0新增
实现Callable接口的步骤如下: .创建一个实现Callable的实现类 2.实现call方法,将此线程需要执行的操作声明在call()中 3.创建Callable接口实现里类的对象 4.将此Callable接口实现类对象作为传递到FutureTask构造器中,创建FutureTask的对象 5.将FutureTask的对象作为参数传递到Thread类的构造器中,创建Thread对象,并调用start()方法 6.获取Callable中call方法的返回值
代码实现:
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对象,并调用start()方法 new Thread(futureTask).start(); try { //6.获取Callable中call方法的返回值 //get()返回值即为FutureTask构造器在参数Callable实现类重写的call()的返回值。 Object num = futureTask.get(); System.out.println("总和为:"+ num); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } } //1.创建一个实现Callable的实现类 class NumThread implements Callable{ //2.实现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; } }创建线程的方式四:使用线程池
好处: 1.提高响应速度(减少了创建新线程的时间) 2.降低资源消耗(重复利用线程池中线程,不需要每次都创建) 3.便于线程管理
corePoolsize:核心池的大小maximumPoolsize:最大线程数keepAliveTime:线程没有任务时最多保持多长时间后会终止代码实现:
public class ThreadPool { public static void main(String[] args) { //1.提供指定线程数量的线程池 ExecutorService service = Executors.newFixedThreadPool(10); ThreadPoolExecutor service1 = (ThreadPoolExecutor) service; //设置线程池的属性 System.out.println(service.getClass()); // service1.setMaximumPoolSize(15); // service1.setKeepAliveTime(10,TimeUnit.DAYS); //2.执行指定的线程的操作。需要提供实现Runnable接口或者Callable接口实现类的对象 service.execute(new NumberThread());//适合适用于Runnable service.execute(new NumberThread1());//适合适用于Runnable // service.submit();//适合使用于Callable //3.关闭连接池 service.shutdown(); } } 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); } } } }多线程知识的学习
多线程(1):https://blog.csdn.net/weixin_45606067/article/details/107068938 多线程(2):https://blog.csdn.net/weixin_45606067/article/details/107067802 多线程(3):https://blog.csdn.net/weixin_45606067/article/details/107067857