1、线程和进程
一个应用程序只有加载到内存中,并由系统为它分配资源后才能执行,而这一执行的程序称为一个进程。因为一个进程只能做一件事,为了使一个进程能够同时做几件事,引入线程的概念,它是比进程更小的运行单位。线程需要在进程中开辟栈空间来实现独立运行(运行依赖于进程),当开辟多个栈空间就可以实现多个线程的并发运行,即可以实现一个进程下执行多个任务。
注意: 1、一个线程只能属于一个进程,而一个进程可以拥有多个线程,但至少得有一个线程。(线程是操作系统可识别的最小执行和调度单位。)
2、同一进程下的多个线程共享该进程的所有资源。
3、在处理机(包括中央处理器,主存储器, I/O 接口)上运行的实质是线程。
4、进程有独立的地址空间,而线程并没有。
参考链接:https://www.cnblogs.com/inception6-lxc/p/9073983.html
2、Java线程的定义
- 继承自Thread类
Class ThreadDemo extends Thread{ @Override public void run(){ System.out.println("this is a thread"); } }
- 实现Runnable接口
Class RunnableDemo implements Runnable{ @Override public void run(){ System.out.println("this is a thread"); } }
二者的使用:
public class test{
public static void main(String [] args){
ThreadDemo thread = new ThreadDemo();
thread.start(); //Thread子类运行线程
RunnableDemo runnable = new Runnable();
new Thread(runnable).start(); //Runnable接口运行线程
}
}
注意: 1、继承自Thread类没有很强的复用性,而其他类都可以实现Runnable接口。
2、Runable接口只能够重写run方法,Thread的子类可以重写任一方法。
3、线程的安全问题
如果一个问题里每个任务的执行都需要保持相互独立,比如经典的卖票问题,当所有线程都抢占同一张票时,每个线程都会执行这一项任务,而票只有一张,这样就导致了线程的安全问题。而解决问题的办法就是使线程同步执行,当一个线程执行的时候,其他线程等候。
实现线程同步执行的三种方式:
-
同步代码块:synchronized(Object)里包含的代码(Object为对象类型,一般为定义的线程类)
Class ThreadDemo1 extends Thread(){ Object object = new Object(); @Override public void run(){ while(true){ /* 同步代码块 */ synchronized(object){ System.out.println("this is a thread"); } //Object也可以是this、ThreadDemo1.class } } }
-
同步方法:定义一个同步类型的方法
Class ThreadDemo2 extends Thread(){ @Override public void run(){ while(true){ pay(); } } /* 同步方法 */ public synchronized void pay(){ System.out.println("this is a thread"); } }
-
同步锁:使用锁对象
Class ThreadDemo3 extends Thread(){ //定义锁对象 Lock lock = new ReentrantLock(); //ReentrantLock为重入锁 @Override public void run(){ while(true){ /* 同步锁 */ lock.lock(); //上锁 try{ System.out.println("this is a thread"); }finally{ lock.unlock(); } } } }
4、线程的状态图
5、Java线程执行的原理图
6、补充
- 等待唤醒机制 :依赖于Object对象的wait()方法和notify()方法。
- ReentrantLock对象 :可以实现公平锁
- 线程池: 通过Executors对象和ExecutorService接口进行线程池的创建和使用
笔记内容可能存在瑕疵,希望读者能够批评指正!