进程是应用程序的执行实例有独立的内存空间和系统资源。
线程是进程中执行运算的最小单位,可完成一个独立的顺序控制流程
一。一个进程可以包含多个线程,每个线程都独立执行特定的任务,
是CPU调度和分派的基本单位。
多线程的概念:
多线程的好处:
主线程:
Thread类
Java提供了java.lang.Thread类支持多线程编程
主线程
public static void main(String args[]) {
Thread t= Thread.currentThread();
System.out.println("当前线程是: "+t.getName());
t.setName("MyJavaThread");
System.out.println("当前线程名是: "+t.getName()); }
在Java中,可以通过继承Thread类或实现Runnable接口来创建线程。
public class MyThread extends Thread {
public void run() {
// 线程执行的代码
}
}
// 创建并启动线程
MyThread thread = new MyThread();
thread.start();
补充:
多线程里的多个线程交替执行,而不是真正的“并行”。
线程每次执行时长由分配的CPU时间片长度决定。
public class MyRunnable implements Runnable {
public void run() {
// 线程执行的代码
}
}
// 创建并启动线程
MyRunnable runnable = new MyRunnable();
Thread thread = new Thread(runnable);
thread.start();
run()方法:直接调用线程对象的run()方法会在当前线程中执行该方法的代码,就像普通的方法调用一样。并不会创建新的线程,而是在当前线程中按顺序执行。所以只有主线程main一条执行路径。
start()方法:调用线程对象的start()方法会创建一个新的线程,并在新的线程中执行run()方法的代码。start()方法会启动线程的执行,然后立即返回,不会阻塞当前线程。所以具体执行过程有多条执行路径,主线程和子线程并行交替执行
总结来说,直接调用run()方法只会在当前线程中执行方法的代码,不会创建新的线程。而调用start()方法会创建新的线程,并在新线程中执行方法的代码。通常情况下,我们应该使用start()方法来启动线程,以实现多线程并发执行的效果。
继承Thread类:
实现Runnable接口
线程在生命周期中有多个状态:
线程共包括以下 5 种状态:
下面是使用Markdown语法写的嵌套列表:
线程共包括以下 5 种状态:
新建状态(New): 线程对象被创建后,就进入了新建状态。例如,Thread thread = new Thread()
。
就绪状态(Runnable): 也被称为“可执行状态”。线程对象被创建后,其它线程调用了该对象的start()
方法,从而来启动该线程。例如,thread.start()
。处于就绪状态的线程,随时可能被CPU调度执行。
运行状态(Running): 线程获取CPU权限进行执行。需要注意的是,线程只能从就绪状态进入到运行状态。
阻塞状态(Blocked): 阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:
wait()
方法,让线程等待某工作的完成。synchronized
同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态。sleep()
或join()
或发出了I/O请求时,线程会进入到阻塞状态。当sleep()
状态超时、join()
等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。死亡状态(Dead): 线程执行完了或者因异常退出了run()
方法,该线程结束生命周期。
线程调度指操作系统或Java虚拟机按照特定机制为多个线程分配CPU的使用权。Java提供了一些常用的线程调度方法:
方法 | |
---|---|
void setPriority(int newPriority) | 更改线程的优先级 |
static void sleep(long millis) | 在指定的毫秒数内让当前正在执行的线程休眠 |
void join() | 等待该线程终止 |
static void yield() | 暂停当前正在执行的线程对象,并执行其他线程 |
void interrupt() | 中断线程 |
boolean isAlive() | 测试线程是否处于活动状态 |
public static void main(String[] args) {
Thread t1 = new Thread(new MyThread(),"线程A");
Thread t2 = new Thread(new MyThread(),"线程B");
t1.setPriority(Thread.MAX_PRIORITY);
t2.setPriority(Thread.MIN_PRIORITY);
//省略代码……
}}
try {
Thread.sleep(1000); // 暂停1秒
} catch (InterruptedException e) {
e.printStackTrace();
}
Thread.yield();
public final void join()
public final void join(long mills)
public final void join(long mills,int nanos)
Thread thread1 = new Thread();
Thread thread2 = new Thread();
thread1.start();
thread2.start();
try {
thread1.join(); // 等待thread1执行完毕
thread2.join(); // 等待thread2执行完毕
} catch (InterruptedException e) {
e.printStackTrace();
}
5.public static void yield()线程的礼让
只是提供一种可能,但是不能保证一定会实现礼让
public class MyThread implements Runnable{
public void run(){
for(int i=0;i<5;i++){
System.out.println(Thread.currentThread().
getName()+"正在运行:"+i);
if(i==3){
System.out.print("线程礼让:");
Thread.yield();
} } }}
多个线程访问共享资源时可能会出现数据不一致的问题,需要使用同步机制来保证线程安全。
public synchronized void synchronizedMethod() {
// 同步的方法
}
public void someMethod() {
synchronized (this) {
// 同步的代码块
}
}
Lock lock = new ReentrantLock();
lock.lock(); // 获取锁
try {
// 同步的代码块
} finally {
lock.unlock(); // 释放锁
}
ArrayList vs. Vector:
synchronized
关键字进行同步,保证了线程安全。Hashtable vs. HashMap:
synchronized
关键字进行同步,保证了线程安全。synchronized
关键字进行同步,保证了线程安全。需要注意的是,虽然线程安全的类型在多线程环境下可以保证数据的一致性和正确性,但在性能上可能会有一定的开销。非线程安全的类型在多线程环境下需要额外的同步措施来保证数据的安全性。因此,在选择使用哪种类型时,需要根据具体的需求和场景进行权衡和选择。