1、程序:Program,是一个指令的集合
2、进程:Process,(正在执行中的程序)是一个静态的概念进程是程序的一次静态执行过程,占用特定地的地址空间
每个进程都是独立的,由3部分组成cpu,data,code
缺点:内存的浪费,cpu的负担
3、线程:是进程中一个“单一的连续控制流程”/执行路径
线程又被成为轻量级进程
Threads run at the same time,independently of one another
一个进程可拥有多个并行的线程
一个进程中的线程共享相同的内存单元/内存地址空间->可以访问相同的变量和对象,而且他们从同一堆中分配对象->通信、数据交换、同步操作
由于线程间的通信是在同一地址空间上进行的,所以不需要额外的通信机制,这就使得通信更简便而且信息的传递速度也更快
继承Thread类,重新run方法,调start(启动线程),每次运行相同的代码,出来的结果可能不一样,原因在于多线程谁先抢占资源无法进行认为控制
package com.msbline.threadPkg; public class ThreadDemo extends Thread{ @Override public void run() { for (int i = 0; i < 10; i++){ System.out.println(Thread.currentThread().getName() +"---"+ i); } } public static void main(String[] args) { ThreadDemo threadDemo = new ThreadDemo(); threadDemo.start(); for (int i = 0; i < 10; i++){ System.out.println(Thread.currentThread().getName() +"==="+ i); } } }
实现Runnable接口,重写run方法,创建Thread对象,将刚刚创建好的Runnable的子类实现作为Thread的构造参数,通过Trhead.start()进行启动
package com.msbline.threadPkg; public class ThreadDemo02 implements Runnable{ @Override public void run() { for (int i = 0; i < 10; i++){ System.out.println(Thread.currentThread().getName() +"---"+ i); } } public static void main(String[] args) { ThreadDemo threadDemo = new ThreadDemo(); new Thread(threadDemo).start(); for (int i = 0; i < 10; i++){ System.out.println(Thread.currentThread().getName() +"==="+ i); } } }
1、sleep 方法是属于 Thread 类中的,sleep 过程中线程不会释放锁,只会阻塞线程,让出cpu给其他线程,但是他的监控状态依然保持着,当指定的时间到了又会自动恢复运行状态,可中断,sleep 给其他线程运行机会时不考虑线程的优先级,因此会给低优先级的线程以运行的机会
2、yield和 sleep 一样都是 Thread 类的方法,都是暂停当前正在执行的线程对象,不会释放资源锁,和 sleep 不同的是 yield方法并不会让线程进入阻塞状态,而是让线程重回就绪状态,它只需要等待重新获取CPU执行时间,所以执行yield()的线程有可能在进入到可执行状态后马上又被执行。还有一点和 sleep 不同的是 yield 方法只能使同优先级或更高优先级的线程有执行的机会
3、join,等待调用join方法的线程结束之后,程序再继续执行,一般用于等待异步线程执行完结果之后才能继续运行的场景。例如:主线程创建并启动了子线程,如果子线程中药进行大量耗时运算计算某个数据值,而主线程要取得这个数据值才能运行,这时就要用到 join 方法了
4、wait 方法是属于 Object 类中的,wait 过程中线程会释放对象锁,只有当其他线程调用 notify 才能唤醒此线程。wait 使用时必须先获取对象锁,即必须在 synchronized 修饰的代码块中使用,那么相应的 notify 方法同样必须在 synchronized 修饰的代码块中使用,如果没有在synchronized 修饰的代码块中使用时运行时会抛出IllegalMonitorStateException的异常
多个线程访问同一个共享数据的时候,会出现数据安全问题,比如买票,两个线程同时对一张票进行操作,可能会导致重票的问题
synchronized(共享资源,共享对象,需要是Object的子类){具体执行的代码块}
public class TicketRunnable2 implements Runnable{ private int ticket = 5; @Override public void run() { for(int i = 0; i<100; i++){ try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (this){ if(ticket > 0){ System.out.println(Thread.currentThread().getName()+"正在出售第"+(ticket--)+"票"); } } } } public static void main(String[] args) { TicketRunnable2 ticketRunnable = new TicketRunnable2(); Thread t1 = new Thread(ticketRunnable,"A"); Thread t2 = new Thread(ticketRunnable,"B"); Thread t3 = new Thread(ticketRunnable,"C"); Thread t4 = new Thread(ticketRunnable,"D"); t1.start(); t2.start(); t3.start(); t4.start(); } }
public class TicketRunnable3 implements Runnable{ private int ticket = 5; @Override public void run() { for(int i = 0; i<100; i++){ try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } this.sale(); } } /** * 使用同步方法解决 */ public synchronized void sale(){ if(ticket > 0){ System.out.println(Thread.currentThread().getName()+"正在出售第"+(ticket--)+"票"); } } public static void main(String[] args) { TicketRunnable3 ticketRunnable = new TicketRunnable3(); Thread t1 = new Thread(ticketRunnable,"A"); Thread t2 = new Thread(ticketRunnable,"B"); Thread t3 = new Thread(ticketRunnable,"C"); Thread t4 = new Thread(ticketRunnable,"D"); t1.start(); t2.start(); t3.start(); t4.start(); } }
一般来说,每个线程自己完成自己的任务就可以了,但有时候,线程的处理会依赖另一个线程的数据,所以就需要线程间通信,来达到同步信息的效果。
参考:https://blog.csdn.net/jisuanji12306/article/details/86363390