多线程Demo学习(使用线程池优化多线程编程,Object线程相关的方法)

一.使用线程池的优势

Java中的对象是使用new操作符创建的,如果用new创建大量短生命周期的对象,这种方式性能非常低下。所以为了解决这个问题一些先行者们发明了池技术。 例如对于数据库连接有连接池,一样的对于线程有线程池。 线程池可以极大的简便我们的多线程编程,在需要大量线程的程序编程时,它不仅从编程上简化了,而且性能比new要好。

下面我们这个Demo展示了new和线程池方式创建并允许线程的性能:

任务类:

public class TempThread implements Runnable {// 测试用的Runnable接口实现类
    private int id = 0;

    @Override
    public void run() {// run()方法给id做自增运算
        id++;
    }
}

主类:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPoolTest {
    public static void main(String[] args) {

        Runtime run = Runtime.getRuntime();// 创建Runtime对象
        
        //不使用线程池创建1000个对象需要的开销
        //*******************************************************************************************************************************************
        run.gc();// 运行垃圾回收器,这样可以减少误差
        long freeMemory = run.freeMemory();// 获得当前虚拟机的空闲内存
        long currentTime = System.currentTimeMillis();// 获得当前虚拟机的时间

        for (int i = 0; i < 10000; i++) {// 独立运行1000个线程
            new Thread(new TempThread()).start();
        }
        System.out.println("独立运行1000个线程所占用的内存:" + (freeMemory - run.freeMemory()) + "字节");// 查看内存的变化
        System.out.println("独立创建1000个线程所消耗的时间:" + (System.currentTimeMillis() - currentTime) + "毫秒");// 查看时间的变化

        //使用线程池技术创建并运行1000个线程需要的开销
        //************************************************************************************************************************************************
        run.gc();// 运行垃圾回收器
        freeMemory = run.freeMemory();// 获得当前虚拟机的空闲内存
        currentTime = System.currentTimeMillis();// 获得当前虚拟机的时间
        ExecutorService executorService = Executors.newFixedThreadPool(2);// 创建线程池
        for (int i = 0; i < 1000; i++) {// 使用线程池运行1000个线程
            executorService.submit(new TempThread());
        }
        System.out.println("使用连接池运行1000个线程所占用的内存:" + (freeMemory - run.freeMemory()) + "字节");// 查看内存的变化
        System.out.println("使用连接池创建1000个线程所消耗的时间:" + (System.currentTimeMillis() - currentTime) + "毫秒");// 查看时间的变化
    }
}

运行结果:
在这里插入图片描述
从结果可以看出:使用线程池可以大大优化普通情况下的多线程编程。

二.了解Object类中线程相关的方法

我们都知道Object类是所有java类的祖先类,在该类中定义了3个与线程操作相关的方法,分别是:

方法名作用
notify()唤醒在此对象监视器上等待的单个线程
notifyAll()唤醒在此对象监视器上等待的所有线程
wait()在其他线程调用此对象的notify()方法或notifyAll()方法前,导致当前线程等待
wait(long timeout)在其他线程调用此对象的notify()或notifyAll()之前,或者超过指定的时间量前,导致当前线程等待
wait(long timeout,int nanos)在其他线程调用此对象的notify()或notifyAll()方法或者其他某个线程中断当前线程,或者超时,导致当前线程等待

下面我们通过使用上面的方法实现线程间的协调工作(实现消费者生产者):

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.LinkedList;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingConstants;
import javax.swing.border.EmptyBorder;
import java.awt.Font;
import javax.swing.UIManager;

public class ProducerAndConsumerFrame extends JFrame {

    private static final long serialVersionUID = -1644485036183526329L;
    private JPanel contentPane;
    private final LinkedList<String> list = new LinkedList<String>();
    private static final int MAX = 10;
    private volatile int count;
    private JTextArea producerTextArea;
    private JTextArea consumerTextArea;
    private JTextArea storageTextArea;
    
    public static void main(String[] args) {
        try {
            UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
        } catch (Throwable e) {
            e.printStackTrace();
        }
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    ProducerAndConsumerFrame frame = new ProducerAndConsumerFrame();
                    frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    public ProducerAndConsumerFrame() {
        setTitle("\u751F\u4EA7\u8005\u548C\u6D88\u8D39\u8005\u95EE\u9898");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(100, 100, 450, 300);
        contentPane = new JPanel();
        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        setContentPane(contentPane);
        contentPane.setLayout(new BorderLayout(0, 0));

        JPanel buttonPanel = new JPanel();
        contentPane.add(buttonPanel, BorderLayout.SOUTH);

        JButton startButton = new JButton("\u5F00\u59CB\u751F\u4EA7");
        startButton.setFont(new Font("微软雅黑", Font.PLAIN, 16));
        startButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                do_startButton_actionPerformed(arg0);
            }
        });
        buttonPanel.add(startButton);

        JPanel resultPanel = new JPanel();
        contentPane.add(resultPanel, BorderLayout.CENTER);
        resultPanel.setLayout(new GridLayout(1, 3, 5, 5));

        JPanel producerPanel = new JPanel();
        resultPanel.add(producerPanel);
        producerPanel.setLayout(new BorderLayout(0, 0));

        JLabel producerLabel = new JLabel("\u751F\u4EA7\u8005");
        producerLabel.setFont(new Font("微软雅黑", Font.PLAIN, 16));
        producerLabel.setHorizontalAlignment(SwingConstants.CENTER);
        producerPanel.add(producerLabel, BorderLayout.NORTH);

        JScrollPane producerScrollPane = new JScrollPane();
        producerPanel.add(producerScrollPane, BorderLayout.CENTER);

        producerTextArea = new JTextArea();
        producerTextArea.setFont(new Font("微软雅黑", Font.PLAIN, 16));
        producerScrollPane.setViewportView(producerTextArea);

        JPanel consumerPanel = new JPanel();
        resultPanel.add(consumerPanel);
        consumerPanel.setLayout(new BorderLayout(0, 0));

        JLabel consumerLabel = new JLabel("\u6D88\u8D39\u8005");
        consumerLabel.setFont(new Font("微软雅黑", Font.PLAIN, 16));
        consumerLabel.setHorizontalAlignment(SwingConstants.CENTER);
        consumerPanel.add(consumerLabel, BorderLayout.NORTH);

        JScrollPane consumerScrollPane = new JScrollPane();
        consumerPanel.add(consumerScrollPane, BorderLayout.CENTER);

        consumerTextArea = new JTextArea();
        consumerTextArea.setFont(new Font("微软雅黑", Font.PLAIN, 16));
        consumerScrollPane.setViewportView(consumerTextArea);

        JPanel storagePanel = new JPanel();
        resultPanel.add(storagePanel);
        storagePanel.setLayout(new BorderLayout(0, 0));

        JLabel storageLabel = new JLabel("\u4ED3\u5E93");
        storageLabel.setFont(new Font("微软雅黑", Font.PLAIN, 16));
        storageLabel.setHorizontalAlignment(SwingConstants.CENTER);
        storagePanel.add(storageLabel, BorderLayout.NORTH);

        JScrollPane storageScrollPane = new JScrollPane();
        storagePanel.add(storageScrollPane, BorderLayout.CENTER);

        storageTextArea = new JTextArea();
        storageTextArea.setFont(new Font("微软雅黑", Font.PLAIN, 16));
        storageScrollPane.setViewportView(storageTextArea);
    }

    protected void do_startButton_actionPerformed(ActionEvent arg0) {

        new Thread(new Producer()).start();
        new Thread(new Consumer()).start();

    }

    private class Producer implements Runnable {
        public void run() {
            for (int i = 0; i < MAX; i++) {// 向仓库中添加商品,MAX是仓库的最大容量
                synchronized (list) {// 使用同步块来解决同步问题
                    String storage = storageTextArea.getText();// 获得文本域内容
                    String text = producerTextArea.getText(); // 获得文本域内容
                    if (list.size() == MAX) {// 如果仓库装满就等待
                        storageTextArea.setText(storage + "仓库已满\n");
                        try {
                            list.wait();// 开始等待
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    } else {
                        String product = "Java编程宝典";
                        list.add(product);// 向仓库中添加商品
                        list.notify();// 唤醒等待的线程
                        producerTextArea.setText(text + "生产:" + product + "\n");
                        count++;// 仓库中商品的数量加一
                        storageTextArea.setText(storage + "仓库中还有" + count + "个商品\n");
                        try {
                            Thread.sleep(100);// 当前线程休眠0.1秒
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }

    private class Consumer implements Runnable {
        public void run() {
            for (int i = 0; i < MAX; i++) {
                synchronized (list) {
                    String storage = storageTextArea.getText();
                    String text = consumerTextArea.getText();
                    if (list.size() == 0) {
                        storageTextArea.setText(storage + "仓库已空\n");
                        try {
                            list.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    } else {
                        consumerTextArea.setText(text + "消费:" + list.removeLast() + "\n");
                        list.notify();
                        count--;
                        storageTextArea.setText(storage + "仓库中还有" + count + "个商品\n");
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }

                }
            }
        }
    }
}

运行效果:
在这里插入图片描述
它的运行逻辑也不难理解:
生产者每次循环都会进行判断是否已经放满了,如果满了,就进入等待状态。如果没满就加入并唤醒等待的消费者线程。
消费者每次循环也会进行判断是否已经空了,如果空了就进入等待,如果不为空就消费并唤醒等待的生产者线程。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员小牧之

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值