📅  最后修改于: 2023-12-03 15:07:17.116000             🧑  作者: Mango
Java线程状态包括:新建(New)、就绪(Runnable)、阻塞(Blocked)、运行(Running)和死亡(Dead)五种状态。状态之间的转换如下:
start()
方法。start()
方法。Thread.yield()
方法。线程安全是指在多线程环境下,程序仍然能够正确地执行。实现线程安全的方法有:
ConcurrentHashMap
、CopyOnWriteArrayList
等。synchronized
关键字对方法或代码块进行加锁控制。Lock
接口及其实现类控制代码块的并发访问。volatile
关键字保证变量的可见性,避免出现脏读、重排序等问题。synchronized
是Java关键字,可以用于修饰方法或代码块实现同步。它的实现依赖于Java虚拟机,性能比较好,但灵活性较差。
Lock
接口是Java5中新增的接口,通过Lock可以实现更灵活、更精确的线程同步。它比synchronized
更加灵活,支持公平锁、非公平锁、可重入锁等特性,但是由于Lock在使用时需要手动获取锁和释放锁,使用不当容易导致死锁等问题。
Thread.sleep()
方法和wait()
方法的区别如下:
Thread.sleep()
是Thread类的静态方法,让当前线程睡眠一段时间,不会释放锁。wait()
是Object类的方法,让线程等待并释放锁。sleep()
方法不需要获取锁。调用wait()
方法前必须获取锁。wait()
方法后,线程将阻塞等待,直到其他线程调用notify()
或notifyAll()
方法唤醒该线程。调用sleep()
方法后,线程将一直睡眠,直到经过指定的时间或其他线程中断该线程。线程池是一种线程复用的机制,通过预先创建一些线程并维护一个线程队列来提高线程的使用效率和响应时间。
创建线程池的方法如下:
ExecutorService threadPool = Executors.newFixedThreadPool(10);
这里创建了一个固定大小的线程池,大小为10。Executors
是一个工具类,提供了许多静态方法,可以用来创建不同类型的线程池。
线程池的好处如下:
Java中的线程是抢占式调度的。当有多个线程在竞争CPU资源时,Java虚拟机会根据线程的优先级和其他状态对线程进行抢占式调度。
Java内存模型是Java程序中所有线程共享的内存区域的抽象。在JMM中,所有变量都存储在主内存中,每个线程还有自己独立的工作内存,工作内存保存了主内存中变量的副本。
在JMM中,线程之间的通信通过主内存进行,在进行读写操作时会从主内存中读取变量的值或将变量的值写回到主内存中。由于JMM的存在,可能会出现变量读写顺序的重排序、数据竞争等问题,影响程序的正确性和性能。
守护线程是一种特殊的线程,它会在所有非守护线程结束后自动退出。守护线程在Java中的应用比较广泛,例如JVM的垃圾回收线程就是守护线程。
创建守护线程的方法如下:
Thread thread = new Thread(runnable);
thread.setDaemon(true);
thread.start();
这里使用setDaemon(true)
方法设置线程为守护线程。注意,必须在调用start()
方法之前调用setDaemon()
方法。
ThreadLocal是Java中的一个线程局部变量,每个线程都有自己的ThreadLocal变量副本。不同线程之间互不干扰,可以保证线程安全。
ThreadLocal常用于保存线程上下文信息、数据库连接、记录当前用户等场景。
同步锁是Java中用于实现多线程同步的机制,通过对共享资源加锁来保证只有一个线程可以访问该资源。Java中提供了两种实现同步锁的机制:synchronized和Lock。
synchronized
通过对方法或代码块块进行加锁来实现线程同步。它具有以下特性:
实现同步锁的另一种方式是使用Lock
接口及其实现类。Lock
具有更灵活、更加精确的特性,例如支持公平锁、非公平锁、可重入锁等。
使用Lock
接口实现线程同步的代码如下:
Lock lock = new ReentrantLock();
lock.lock();
try {
// 具体业务逻辑
} finally {
lock.unlock();
}
线程之间可以通过共享变量、管道、信号量、自旋锁等方式进行通信。其中最重要的是共享变量的方式,Java中的synchronized
和volatile
关键字都是基于共享变量实现线程之间的通信的。
线程死锁是指两个或多个线程互相持有对方需要的资源而无法继续执行的状态。线程死锁通常是程序设计或资源分配问题造成的,一旦出现会导致系统停止响应,严重影响程序的正确性和性能。
线程饥饿是指某个线程无法获得所需的资源而无法继续执行的状态。通常是由于低优先级线程得不到资源,而高优先级线程占用了资源造成的。
线程优先级是指线程在竞争CPU资源时的优先级,有10个级别,范围从1到10,其中10为最高优先级。可以通过setPriority()
方法设置线程的优先级,如下:
Thread thread = new Thread(runnable);
thread.setPriority(Thread.MAX_PRIORITY);
thread.start();
这里设置了线程的优先级为最大优先级。
CountDownLatch是Java中的一个同步工具,可以用于控制多个线程之间的执行顺序,特别是一个线程A需要等待多个其他线程B、C、D等处理完之后才能执行。
使用CountDownLatch的方法如下:
CountDownLatch latch = new CountDownLatch(3); // 创建一个计数器,初始值为3
// 在多个线程中调用latch.countDown()方法,减少计数器的值
latch.await(); // 等待所有线程执行完毕
这里同时创建了三个线程执行某个业务逻辑,这三个线程都会在执行完毕后调用latch.countDown()
方法,最后主线程再调用latch.await()
方法等待这三个线程完成。
闭锁也是一种同步工具,与CountDownLatch类似,用于暂停线程的执行,等待满足条件后再继续执行。不同之处在于,闭锁可以重复使用,而CountDownLatch只能使用一次。
Java中提供了一个java.util.concurrent.CyclicBarrier
类实现闭锁的功能。
线程池的拒绝策略是指当线程池的任务队列已满时,预定义的线程池可以采取的策略。JDK中提供了以下四种预定义的拒绝策略:
可以通过调用ThreadPoolExecutor
的构造方法来指定线程池使用的拒绝策略。