随着硬件技术的不断提升,计算机的性能越来越快,人们也越来越需要通过多线程技术来提升软件的性能。Java作为一门面向对象的语言,其多线程编程实践非常重要,很多Java开发人员都需要掌握相关技术。
一、多线程背景知识
1、线程的创建方式
Java中创建一个线程有两种方式:继承Thread类和实现Runnable接口。使用继承Thread类的方式可以重写Thread中的run()方法,使用实现Runnable接口的方式需要自己定义一个run()方法并在创建线程时传入。
public class MyThread extends Thread{ @Override public void run(){ //do something } } public class MyRunnable implements Runnable{ @Override public void run(){ //do something } } //创建线程 MyThread t = new MyThread(); t.start(); MyRunnable r = new MyRunnable(); Thread t = new Thread(r); t.start();
2、线程的状态转换
Java中线程的状态有如下几种:新建、就绪、运行、阻塞和死亡。线程的状态可以通过Thread类的getState()方法获取,也可以通过Thread.State枚举类来获取。
Thread t = new Thread(); t.start(); //线程就绪 t.join(); //线程阻塞 t.interrupt(); //中断阻塞线程 t.stop(); //强制结束线程
二、线程同步和锁
1、synchronized关键字
Java中的synchronized关键字可以实现线程同步,多线程访问共享资源时可以使用synchronized来保证线程安全。
public class MyCounter{ private int count; //加锁,只有一个线程进入方法,其他线程等待 public synchronized void increment(){ count++; } } //使用 MyCounter counter = new MyCounter(); Thread t1 = new Thread(() -> { for(int i=0;i<1000;i++){ counter.increment(); } }); Thread t2 = new Thread(() -> { for(int i=0;i<1000;i++){ counter.increment(); } }); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println(counter.getCount()); //2000
2、ReentrantLock
ReentrantLock是Java中的一个锁,相比synchronized关键字,它可以手动控制锁的获取和释放。
public class MyCounter{ private int count; private ReentrantLock lock = new ReentrantLock(); public void increment(){ lock.lock(); //加锁 try{ count++; }finally{ lock.unlock(); //释放锁 } } } //使用 MyCounter counter = new MyCounter(); Thread t1 = new Thread(() -> { for(int i=0;i<1000;i++){ counter.increment(); } }); Thread t2 = new Thread(() -> { for(int i=0;i<1000;i++){ counter.increment(); } }); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println(counter.getCount()); //2000
三、多线程实战案例
1、生产者-消费者模型
生产者-消费者模型是一个典型的多线程问题,其中一个或多个生产者线程生成数据并将其传递给一个或多个消费者线程,消费者线程使用数据。
public class ProducerConsumer{ private int count; private LinkedListqueue = new LinkedList<>(); private Object lock = new Object(); public void produce(){ synchronized(lock){ while(queue.size() == count){ //队列满了,等待消费者 try{ lock.wait(); }catch(Exception e){} } int num = new Random().nextInt(100); System.out.println("Producing: " + num); queue.add(num); lock.notifyAll(); //唤醒所有等待线程 } } public void consume(){ synchronized(lock){ while(queue.size() == 0){ //队列为空,等待生产者 try{ lock.wait(); }catch(Exception e){} } int num = queue.removeFirst(); System.out.println("Consuming: " + num); lock.notifyAll(); //唤醒所有等待线程 } } } //使用 ProducerConsumer pc = new ProducerConsumer(); Thread t1 = new Thread(() -> { for(int i=0;i<10;i++){ pc.produce(); } }); Thread t2 = new Thread(() -> { for(int i=0;i<10;i++){ pc.consume(); } }); t1.start(); t2.start(); t1.join(); t2.join();
2、多线程并发执行任务
在实际生产开发中,经常需要以多线程形式执行某个任务,这时可以使用Thread类、Callable接口或者线程池来实现。以下是使用ExecutorService线程池来并发执行任务的例子。
ExecutorService executor = Executors.newFixedThreadPool(4); List> results = new ArrayList<>(); for(int i=0;i<10;i++){ int num = i; Future result = executor.submit(() -> { System.out.println("Thread " + num + " start"); try{ Thread.sleep(1000); //模拟任务执行时间 }catch(Exception e){} System.out.println("Thread " + num + " end"); return num; }); results.add(result); } executor.shutdown();
四、结束语
通过对Java多线程技术的了解和实践,可以提高软件的并发处理能力和运行效率。在实际应用中,需要根据具体情况选择适当的线程同步和锁机制,合理使用多线程提高程序的性能和响应速度。