多线程基本知识

一、基本概念

一个应用程序就是一个进程,操作系统上可以有多个进程,一个进程中可以有多个线程。

一个CPU一个时刻只能运行一个线程,当有多个CPU时可以同时并行运行多个线程,但是线程数大于CPU数时,会有线程处于阻塞状态。

二、线程的生命周期

状态:新建、就绪、运行、阻塞、死亡。

阻塞:线程没有获取CPU资源,不能执行


三、控制线程状态

join()方法:在thread1中执行thread2_instance.join()方法时,thread1线程阻塞,thread2线程进入运行状态;只有当thread2结束后thread1才会运行。

sleep()方法:thread1中调用Thread.sleep()方法时,thread1线程进入阻塞状态,不释放锁

yield()方法:thread1中调用Thread.yield()方法时,thread1进入就绪状态。

wait()、noitfy()、notifyAll()方法

四、线程同步

同步问题:当多个线程并发修改某个对象时,就会出现同步问题。

控制同步:

线程的目的是操作对象,那么在线程类中把“目标对象作为成员变量”,然后“使用代码来操作、修改对象”。

使用锁来控制同步,当某线程获取锁之后,只有执行完同步代码(中间没调用wait()方法或没有被异常中断)才释放锁,其它线程才会获取锁来操作锁对象。

1、同步代码块

把操作修改对象的代码块变成同步代码块,目标对象作为锁对象。

2、同步方法

把操作修改对象的代码块变到对象类的实例方法中,把实例方法变成同步方法。通过对象调用此方法修改自己时,自己就是锁对象。

3、使用lock对象

把可能出现同步问题的代码块上锁,执行完后解锁。能保证

package grammar;

import java.util.concurrent.locks.ReentrantLock;

//被共同访问、修改的对象
class Account {
	public int num;
	//锁对象
	private final ReentrantLock lock = new ReentrantLock();

	public Account(int num) {
		this.num = num;
	}
	//调用此方法的对象就是“上锁对象”,线程获得该对象才能调用此方法
//	public synchronized void draw(int drawAmout){
	public void draw(int drawAmout){
		//加锁,使用Lock对象作为锁对象
		lock.lock();
		if (num >= drawAmout) {
			System.out.println("开始取钱");
			try {
				Thread.sleep(1);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			num = num - drawAmout;
			System.out.println(num);
			System.out.println("结束取钱");
		//释放锁
		lock.unlock();	
		}
	}
}

// 修改对象的线程
class DrawThread extends Thread {
	// 被共访修改的对象
	private Account account;
	private int drawAmout;

	public DrawThread(Account account, int drawAmount) {
		this.account = account;
		this.drawAmout = drawAmount;
	}

	// 修改方法
	public void run() {	
		//account调用同步方法,则account是上锁对象
		account.draw(100);
		
		/**同步代码块
		//把共访修改对象作为上锁对象,只有线程获得该对象才执行“同步代码块”
		synchronized (account) {
			if (account.num >= drawAmout) {
				System.out.println("开始取钱");
				try {
					// 强制让线程阻塞
					Thread.sleep(1);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				account.num = account.num - drawAmout;
				System.out.println(account.num);
				System.out.println("结束取钱");
			}
		}
		*/
		
	}
}

public class MyThread {

	public static void main(String[] args) {

		Account account = new Account(100);

		DrawThread thread1 = new DrawThread(account, 100);
		DrawThread thread2 = new DrawThread(account, 100);
		thread1.start();
		thread2.start();

		try {
			// main线程阻塞,先不打印
			Thread.sleep(10);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		System.out.println("主线程");
		System.out.println(account.num);
		System.out.println("主线程");

	}

}

五、线程间通信

借助Object的三个方法:wait()、notify()、notifyAll(),只能在同步方法(直接调用)和同步代码块(锁对象调用)中调用。

wait()方法:在thread1中使用锁对象.wait()方法,thread1进入阻塞状态,释放锁。被notify()唤醒or超时后依然处于阻塞态,只有再次获取锁后才处于就绪态。而sleep()的线程醒后就是就绪态。

notify()方法:在thread1中使用锁对象.notify()方法通知被wait()的线程后,thread1先执行完,再释放锁,其它需要获得此锁的线程才可能运行。若不使用notify()方法通知被wait()的线程,即使thread1执行完了释放锁,被wait()了的线程(超时后醒来可去竞争锁对象)任然不能和其它线程进行竞争,从而获得执行机会。

wait()和notify()意义







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值