一个CPU核心时,这种并行实际上是在CPU时间片轮换的基础上实现的并发。在多核处理器系统中,多个线程可以在不同的CPU核心上真正并行执行。
二、创建线程
在Java中,创建线程主要有两种方式:
1. 继承Thread类:自定义一个新的类,该类继承Thread类,然后重写run()方法。创建此类的实例并调用start()方法,即可启动新线程。
2. 实现Runnable接口:创建一个实现了Runnable接口的类,实现run()方法。然后将Runnable对象作为参数传递给Thread类的构造函数,创建Thread对象并调用start()方法启动线程。
三、线程常用方法
- 线程的优先级:Java中的Thread类提供了设置和获取线程优先级的方法,如setPriority(int priority)和getPriority(),优先级较高的线程在调度时可能有更多的机会获得CPU时间片。
- 线程的休眠:通过调用Thread.sleep(long millis)可以让线程暂停执行指定的毫秒数,进入阻塞状态。
- 线程的让步:Thread.yield()方法可以让当前运行的线程暂停,让其他相同优先级的线程有机会执行。
- 线程的合并:join()方法可以使调用此方法的线程等待目标线程结束后再继续执行。
四、守护线程
通过调用Thread.setDaemon(true)方法,可以将线程设置为守护线程。守护线程不阻止程序的退出,只有当所有非守护线程结束时,程序才会终止。
五、线程生命周期
线程有五种基本状态:新建、可运行、运行、阻塞和终止。线程状态之间的转换受到调度策略和同步机制的影响。
六、线程安全
为了解决多线程环境下数据的一致性和完整性,Java提供了多种同步机制:
- 同步代码块:synchronized关键字可以用于包围一段代码,确保同一时间只有一个线程可以执行该代码块。
- 同步方法:将整个方法声明为synchronized,同样实现线程同步。
- Lock接口:如ReentrantLock,提供更细粒度的锁控制,支持公平锁和非公平锁,以及可中断和可定时的锁等待。
七、线程通信
线程间通信主要通过wait(), notify()和notifyAll()方法实现,这些方法必须在同步上下文中使用,用于控制线程的等待和唤醒,实现资源的共享。
八、死锁
当两个或多个线程相互等待对方释放资源而形成的一种僵局,称为死锁。避免死锁的关键在于正确设计资源的分配和线程的执行顺序。
九、线程池
线程池可以有效管理线程的创建和销毁,提高系统的性能和响应速度。Java的ExecutorService接口和ThreadPoolExecutor类提供了线程池的实现。Callable接口允许返回一个结果值,可以与Future和ExecutorService结合使用。
十、线程安全集合
Java并发包提供了一些线程安全的集合类,如:
- CopyOnWriteArrayList:在添加、删除元素时,会复制原有数组并创建新的数组,保证并发访问的安全性,适用于读多写少的情况。
- CopyOnWriteArraySet:基于CopyOnWriteArrayList的线程安全集合,用于存储唯一元素。
- ConcurrentHashMap:线程安全的哈希映射,相比synchronized Map,提供了更高的并发性能。
总结,多线程编程涉及到并发、并行的概念,线程的创建、管理和同步,以及线程间的通信和避免死锁的策略。在实际开发中,合理利用这些知识可以优化程序性能,实现高效并发处理。