Java 多线程

Java 多线程

进程:运行中的应用程序为进程,进程拥有cup和内存资源
线程:线程是进程的最小单位,一个进程包含多个线程,线程本身不拥有资源,共享所有进程的资源
多进程:在操作系统中能够同时运行多个任务。
多线程:在同一个应用程序中,多个顺序流在同时执行。
当启动程序,在操作系统中产生一个进程,程序从main方法开始,当程序到main方式的时候,在进程里面开启一个线程(主线程)。整个程序从开始到结束都只有一个线程,这个程序就是个单线程程序。
进程:
1、将应用程序放在内存的代码去,代码放在方法区并没有马上执行,但是这个时候说明一个程序正在准备开始,进程产生并没有运行,所以进程其实是一个静态的概念
2、进程的执行指主线程开始执行了,在机器上运行任务的全都是线程。

创建线程

1、继承Thread类,当前类表示多线程类。

public class MyThread extends Thread{
	/**
	 * 线程体,多线程任务都在run里面执行
	 */
	public MyThread(String name){
		super(name);
	}	

	@Override
	public void run() {
		while (true) {
			System.out.println(Thread.currentThread().getName()+"我是好人");
		}
	}
	
	public static void main(String[] args) {
		//(1)产生一个线程对象
		MyThread t = new MyThread("线程1");
		//(1)产生第二个线程对象
		MyThread t1 = new MyThread("线程2");
		//(2) 启动线程
		t.start();
		t1.start();
		while (true) {
			System.out.println("我是666");
		}
	}
}

2、实现Runable接口,也可以表示多线程。

public class MyThread implements Runable{
	/**
	 * 线程体,多线程任务都在run里面执行
	 */
	@Override
	public void run() {
		while (true) {
			System.out.println("我是好人")}
	}

	public static void main(String[] args) {
		//(1)产生一个线程对象
		MyThread t = new MyThread();
		Thread th = new Thread(t);
		//(2) 启动线程
		th.start();
		while (true) {
			System.out.println("我是666");
		}
	}
}

3、实现Callable接口,也可以实现多线程。
4、线程池
启动线程使用start,而不是调用run
Thread.currentThread()可以获取当前执行的线程,通过它获取线程的名字等。

start()才是启动线程的方法,使用run()线程体(直接调用相当调用方法),产生多线程程序。

start(),将线程放入到线程组(线程队列,先进先出),接下来在调用本地方法start0(),通知虚拟机来执行线程,虚拟机默认会调用线程的run()方法来执行

线程优先级

java 提供了一个线程调度器来监控程序中启动后进入就绪状态的线程,线程调度器会根据线程优先级来判断先调度哪个线程执行。

线程优先级我们用数字1-10来表示,值越大优先级越高,默认缺省值为5(主线程默认为5)。

程序的运行结果还是虚拟机来安排。无法预知运行后的结果,线程优先级高低只是一个参考值,相对的结果,理论上具有高优先权的程序占有更高的cpu使用权,但有时实际结果并不如此。

设置优先级:线程对象.setPriority()
获取优先级:线程对象.getPriority()

线程的生命周期

在这里插入图片描述
五种状态:
1、新建
2、就绪
3、运行
4、阻塞(sleep()join()IO操作yield()
sleep(): Thread.sleep()睡眠,单位为毫秒一旦调用,当前线程处于睡眠状态,当睡眠时间过去后马上恢复到就绪状态。
join():合并两个线程,假设有两个线程A、B,A线程必须等待B运行完了才能继续往下执行,我们可以使用join()来完成这项工作。
yield():在多线程运行过程中,当前抢到cpu资源的线程想让出使用权,调用yeild()方法马上就让出使用权变成就绪状态,但是还可能被jvm分配使用群,在实际开发中,无法保证yield()的让步
IO阻塞,线程会让出cpu。
5、死亡

线程同步

多个线程同时运行,有时候线程之间共享数据,一个线程需要其他线程的数据,否则就不能保证程序运行结果。
并发
同一个时间点多个线程访问同一资源对象。
临界资源:多个线程共享数据,就称为共享资源(临界资源)
线程同步:同步就是协同步调按照预先先后顺序执行,先抢到资源的线程先执行,两个线程相互配合,共享数据。
线程互斥:多个线程共享同一个变量,而且都对变量有修改,如果不考虑在运行过程中相互协调问题,就会出现数据不一样,数据安全问题。

java实现多线程同步:
1、同步块
2、同步方法
3、volatile关键字

{
	 // 同步块 
	synchronized(this) {
	//	代码只能在同一时间一个线程访问
	}
	// 同步方法
	public synchronized void method() {
	}
}

在java中每个对象都有内置锁,当你使用synchronized关键字的时候,内置锁会保护整个方法,在调用方法前需要获取内置锁,否则处于等待状态。

volatile关键字
给局部变量的访问提供了一种免锁机制,一个变量使用它来修饰告诉虚拟机该域可能被其他线程更新,每次使用当前值的时候,都要重新计算一下。默认的值保存在寄存器,所有线程互斥就是直接取寄存器的数据,volatile不会提供任何原子操作,也不能final来修饰。

死锁

在多个线程执行中因为争夺资源而造成的互相等待,若没有外部处理,他们都将无限等待下去(相互将对象锁起来)。

原因:
1、系统资源不足
2、进程的推进顺序有问题
3、资源分配不当

数据线程共享

在java中,可以用wait()notify(),notifyall()完成线程之间的通信,在开发过程中最常见的例子就是生产者和消费者之间的问题,生产者产生数据,消费者取走数据表,生产者将数据放入队列里,消费者可以将数据从队列中获取数据,如果没有数据就处于等待。

wait()notify(),notifyall()都是Object对象提供,主要用来控制线程的状态。

wait():用来将一个线程置入休眠的一个方法,不会自己恢复,必须调用了notify()notifyall()当前线程才会被唤醒。

调用wait()的时候,线程必须要获取到对象级别锁。wait()必须在synchronized中使用,一旦调用了wait(),当前线程就处于休眠状态,当前线程锁就会被释放,其他线程就可以抢资源。

调用notify(),用于唤醒在此对象监视下面等待的单个线程(也就是notify()唤醒,使用了wait()休眠的线程,操作本对象的线程),如果有多个线程在此对象上等待,会随机唤醒一个线程。,并且等待获取对象的对象锁(表示当前就算收到了通知,wait()对象也不会马上获取对象锁,notify()唤醒的线程执行完了才能获取到对象锁)。

notifyAll()唤醒当前对象上所有等待的线程,唤醒的顺序是随机的。
注意:使用notifyAll()的时候必须在synchronized内部完成。
sleep()wait()区别

  • sleep()来自于Thread类,是Thread类中的静态方法,在哪个线程中调用,哪个线程就睡眠。即使在a线程中调用b的sleep()的方法,那也是a线程睡眠。而wait()来自Object类
  • sleep()方法没有释放锁,sleep(millis)可以用时间知道他自动唤醒,如果时间不到只能调用interrupt()强制打断,Thread.Sleep(0)的作用可触发操作系统立刻重新进行一次cpu竞争。而wait()方法释放了锁,使得其他线程可以同步控制块或方法,要等待其他线程调用notify()/notifyAll() 唤醒等待池中的线程,才会进入到就绪等待OS重新分配资源。
  • 使用范围:wait()notify()notifyAll()只能在同步控制方法或同步块中使用,而sleep()可以在任何地方使用。
  • sleep()必须捕获异常,而wait(),notify()notifyAll()不需要捕获异常。

notify()notifyall()区别:

  • 如果线程用了对象的wait()方法,那么线程便会处于该对象的等待池中,等待池中的线程不会去竞争该对象的锁。
  • 当线程调用了对象的notifyAll()方法(唤醒所有的wait()线程)或notify()方法(随机唤醒一个wait()线程),被唤醒的线程便会进入到该对象的锁池中,锁池中的线程就会去竞争该对象的锁。
  • 优先级高的线程竞争到对象锁的概率大,加入没有竞争到对象锁的线程,还是会留在锁池中,唯有线程再次调用wait()方法,它才会重写回到等待池中,而竞争到对象锁的线程则会继续执行下去,直到执行完了synchronized代码块,它就会释放掉该对象,这时锁池中的线程会继续竞争对象锁。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值