多线程

什么是进程?

I. 进程是具有独立功能的程序在某个数据集合上的一次执行过程。进程是系统进行资源分配和调度的一个独立单位。
II. 通俗的讲进程就是:运行中的程序,称为进程。
III. 需要知道的是:单核CPU在任一时间点上,只能运行一个程序。
IV.进程宏观上是并行,微观上是串行。

什么是线程?

I. 线程是进程内的一个执行实体或执行单元,是比进程更小的能独立运行的基本单位。 线程实质上也是一个轻量级进程。
II. 程序中的一个顺序执行流程,也是CPU的基本调度单位。

进程与线程的区别:

操作系统引入线程机制后,进程是资源分配和调度的单位,线程是处理机调度和分配的单位,资源分配给进程,线程只拥有很少资源,线程切换代价比进程低。不同进程地址空间相互独立,同一进程内的线程共享同一地址空间。一个进程的线程在另一个进程内是不可见的。创建进程或撤销进程,系统都要为之分配或回收资源,操作系统开销远大于创建或撤销线程时的开销。

多线程

I. 进程可以由单个或多个线程组成,彼此间完成不同的工作,交替执行,称为多线程。
II. JVM虚拟机是一个进程,默认包含主线程(Main函数),可以通过代码创建多个独立线程,与Main线程并发执行。

线程的组成

I.CPU时间片
II. 运行数据:
(1).堆空间:存储线程需要使用的对象,多个线程可以共享堆中的对象
(2).栈空间:存储线程需要使用的局部变量,每个线程都拥有独立的栈

线程的创建

I. 继承Thread类,自定义类变成线程类

public class TestThread {
	public static void main(String[] args) {
		
		Thread t = new T();//父类引用指向子类对象,创建了线程对象t
		t.start();//启动线程
	}
}

class T extends Thread{
	public void run(){//覆盖run()方法
		System.out.println("T extends Thread");
	}
}

II. 实现Runnable接口,赋予自定义类线程任务的能力。

public class TestRunnable {
	public static void main(String[] args) {
		T2 t = new T2(); //创建实现类对象
		Thread t2 = new Thread(t);//创建线程对象 
		t2.start();//通过线程对象.start()方法启动线程
	}
}	
class T2 implements Runnable{

	@Override
	public void run() {//覆盖run()方法
		System.out.println("T2 implements Runnable");
	}
	
}

使用Runnable接口可以更方便的表示出数据共享的概念

线程的基本状态

在这里插入图片描述

线程中常用方法

I.休眠 sleep(long millis);
(1).当前线程主动休眠 millis毫秒,进入有限期等待!

public class TestThread {
	public static void main(String[] args) {
		
		Thread t = new T();
		t.start();
	}
}

class T extends Thread{
	public void run(){
		try {
			Thread.sleep(2000);//调用sleep()方法 让当前线程等待两千豪秒(两秒)
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("T extends Thread");
	}
}

II. 放弃 yield();
(1).当前线程主动放弃时间片,回到就绪状态,竞争下一次时间片

public class TestThread {
	public static void main(String[] args) {
		
		Thread t = new T();
		t.start();
		for(int i = 1 ; i < 6 ; i++){
			System.out.println("main"+"---"+i);
		}
		
	}
}

class T extends Thread{
	public void run(){
		for(int i = 1 ; i < 6 ; i++){
			Thread.yield();//当前线程主动放弃时间片,回到就绪状态,竞争下一次时间片

			System.out.println("T extends Thread"+"---"+i);
		}
	}
}

III. 结合 join();
(1).允许其他线程加入到当前线程中,当前线程进入无限期等待!

public class TestThread {
	public static void main(String[] args) {
		
		Thread t = new T();
		t.start();
		for(int i = 1 ; i < 6 ; i++){
			System.out.println("main"+"---"+i);
		}
		
	}
}

class T extends Thread{
	public void run(){
		for(int i = 1 ; i < 6 ; i++){
			try {
				this.join();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println("T extends Thread"+"---"+i);
		}
	}
}

在这里插入图片描述
从运行结果可以看出程序并未结束,而是由于join()的加入,导致T一直在等待,即无限期等待

线程的等待状态

在这里插入图片描述

线程安全

I.同步代码块
(1). synchronized(临界资源对象){
//原子操作
}
II.同步方法
(1). synchronized 返回值类型 方法名成(参数列表){
//原子操作
}

注意:
synchronized  同步锁
I.每个对象都有一个互斥锁标记,用来分配给线程。
II.只有持有对象互斥锁标记的线程,才能进入对该对象加锁的同步操作中(同步方法、同步代码块)。
III.只有线程退出同步操作时,才会释放相应的锁标记
同步的规则:
I.只有在调用包含同步代码块的方法或者是同步方法时,才需要对象的锁标记
II.如果调用的是不包含同步代码块的方法或普通方法时,则不需要锁标记,直接调用即可。

线程的阻塞状态

在这里插入图片描述

线程的通信

I.等待
(1)wait();
(2) 必须在对obj(对象)加锁的同步代码块(或同步方法)中,在一个线程执行期间,调用了obj.wait(),该线程会释放所拥有的锁标记。同时,进入到obj的等待队列中。等待唤醒
II. 通知(唤醒)
(1).notify();//唤醒其中一个线程
notifyAll();//唤醒所有的线程
(2).必须在对obj加锁的同步代码块(或同步方法)中,从obj的Waiting(等待队列)中随机释放一个或全部线程。对自身线程无影响。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章