java之多线程,从线程的几种状态说起

最近赶着金三银四的风潮,我也顺应了时代一次,果断辞去工作,加入了找工作的大军当中,面来面去,发现大家都对java多线程这块比较感兴趣,于是在工作安定下来之后,我决定重新梳理一下多线程的知识,当做是一个学习复习笔记,看到的朋友,也请大家指出疏漏之处,在此谢过大家了。好了,话不多说,开始正题。

线程的几种状态:

  1. 新生:用关键字new创建一个线程
  2. 就绪:线程创建后,其它线程调用对象的start()方法,该线程就处于就绪队列当中变得可运行,只等待获取cpu的使用权,通俗点讲就是万事具备,只欠cpu的状态,即除了cpu,其它运行所需资源已全部获取。
  3. 运行:就绪状态的线程获取cpu,执行程序代码
  4. 阻塞:线程因为某种原因放弃cpu的使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。
  • 等待阻塞:运行的线程执行wait()方法,该线程会释放占有的所有资源,JVM会把该线程放入“等待池”中。进入这个状态后,是不能自动唤醒的,必须依靠其它线程调用notify()或notifyAll()方法才能被唤醒
  • 同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入“锁池”中
  • 其它阻塞:运行的线程执行sleep()或join()方法,或者发出了IO请求时,JVM会把该线程置为阻塞状态。当sleep()方法超时,join等待线程终止或者超时,或者IO处理完毕时,线程重新转入就绪状态

5.死亡:线程执行完了或者因异常退出的run()方法,或者执行了stop()方法(不推荐使用这种方式),该线程结束生命周期。

关于生命周期的详细介绍,参考文章:https://www.cnblogs.com/jijijiefang/articles/7222955.html

下面附一个银行取款的小案例来帮助我们理解java多线程的运行机制,话不多说,直接上代码:

共享变量Bank:

package com.cn.bank;
/**
 * 银行
 *
 */
public class Bank {
	//帐户余额
	private int sum =0;
	/**
	 * 存钱
	 * @param money
	 */
	public void addMoney(int money){
		sum += money;
		System.out.println(System.currentTimeMillis()+"存进"+money);
		
	}
	/**
	 * 取钱
	 * @param money
	 */
	public void subMoney(int money){
		if(sum - money<0){
			System.out.println("余额不足");
		}else{
			sum -= money;
			System.out.println(System.currentTimeMillis()+"取出"+money);
		}
	}
	/**
	 * 查询余额
	 */
	public void lookMoney(){
		System.out.println("帐户余额:"+sum);
	}
}

存钱线程:

package com.cn.bank;
/**
 * 存钱线程
 *
 */
public class AddM implements Runnable{
	private Bank bank;
	@Override
	public void run() {
		// TODO Auto-generated method stub
		while (true) {
			synchronized (Bank.class) {
				bank.addMoney(100);
				bank.lookMoney();
				try {
					Thread.sleep(10);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}
	public AddM(Bank bank) {
		super();
		this.bank = bank;
	}

}

取钱线程:

package com.cn.bank;
/**
 * 取钱线程
 *
 */
public class SubM implements Runnable {
	private Bank bank;
	@Override
	public void run() {
		// TODO Auto-generated method stub
		while (true) {
			synchronized (Bank.class) {
				
				bank.subMoney(100);
				bank.lookMoney();
				try {
					Thread.sleep(5);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}
	public SubM(Bank bank) {
		super();
		this.bank = bank;
	}

}

为了能够更好的看到两个线程的交替执行,我分别对两个线程设置了执行时间,两个线程的执行时间设置的不一样,这样做的主要目的,是为了看到余额不足的情况(取钱线程执行时间大于存钱线程)。

测试类:

package com.cn.bank;

public class Test {

	public static void main(String[] args) {
		final Bank bank = new Bank();
		//创建存钱线程
		AddM addM = new AddM(bank);
		Thread th1 = new Thread(addM, "存钱线程");
		//创建取钱线程
		SubM subM = new SubM(bank);
		Thread th2 = new Thread(subM, "取钱线程");
		th1.start();
		th2.start();
	}

}

说几个主要的地方,首先就是要明白,Thread类的开始是在run()方法,这个就相当于我们java中的mian()(其实也是一个线程,我们叫它主线程),我的个人理解是这个线程的所有操作都要在这个run()方法中来实现,共享变量可以通过方法参数的形式进行传入。所以在run()方法中做好同步工作就非常重要了。run()方法是主线程在调用对象执行start()方法之后 自动执行的,不能手动调用。还有就是锁的范围不能太广,此处可以采用细粒度锁来提高程序的性能,关于这个锁的问题,后续还会继续更新笔记,谢谢您的阅读。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值