IMOOC个人笔记 JAVA多线程基础

什么是线程:线程是比进程还要小的运行单位,一个进程包含多个线程。 比如说一个程序是由很多行代码组成的,那么代码可以分成很多块放到线程当中去分别执行,可以认为线程看作一个子程序。
CPU时间片的轮转:
在这里插入图片描述
线程的创建:
在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述通过继承Thread类实现线程:
在这里插入图片描述两个线程同时启动:
在这里插入图片描述总结:线程获得CPU的使用权都是随机的。

通过实现Runnable 线程:
在这里插入图片描述Runnable中的run()方法可以被多个线程共享,可以用于多个线程处理同一个资源的情况。下图中 变量i相当于资源,t1和t2都共享了这个资源。
在这里插入图片描述
在这里插入图片描述在这里插入图片描述线程的状态和生命周期:
在这里插入图片描述sleep方法应用

在这里插入图片描述案例:
在这里插入图片描述join方法应用:
在这里插入图片描述
调用join方法的线程执行结束之后,其他线程才能执行。过了等待终止时间之后,不管该线程有没有执行完毕,其他线程都可以执行。
案例:
在这里插入图片描述在这里插入图片描述线程优先级:
在这里插入图片描述优先级常量:
在这里插入图片描述优先级相关的方法:
在这里插入图片描述 案例:
在这里插入图片描述多线程运行的问题:
在这里插入图片描述案例:
Bank.java

package com.imooc.bank;

public class Bank {
	private String account;// 账号
	private int balance;// 账户余额

	public Bank(String account, int balance) {
		this.account = account;
		this.balance = balance;
	}

	public String getAccount() {
		return account;
	}

	public void setAccount(String account) {
		this.account = account;
	}

	public int getBalance() {
		return balance;
	}

	public void setBalance(int balance) {
		this.balance = balance;
	}

	@Override
	public String toString() {
		return "Bank [账号:" + account + ", 余额:" + balance + "]";
	}

	// 存款
	public void saveAccount() {

		// 获取当前的账号余额
		int balance = getBalance();
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		// 修改余额,存100元
		balance += 100;
		// 修改账户余额
		setBalance(balance);
		// 输出存款后的账户余额
		System.out.println("存款后的账户余额为:" + balance);
	}

	public void drawAccount() {
			// 在不同的位置处添加sleep方法

			// 获得当前的帐户余额
			int balance = getBalance();
			// 修改余额,取200
			balance = balance - 200;
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			// 修改帐户余额
			setBalance(balance);
			System.out.println("取款后的帐户余额:" + balance);
		

	}
}

SaveAccount.java

package com.imooc.bank;
//存款
public class SaveAccount implements Runnable{
	Bank bank;
	public SaveAccount(Bank bank){
		this.bank=bank;
	}
	public void run(){
		bank.saveAccount();
	}
}

DrawAccount.java

package com.imooc.bank;
//取款
public class DrawAccount implements Runnable{
	Bank bank;
	public DrawAccount(Bank bank){
		this.bank=bank;
	}
	@Override
	public void run() {
		bank.drawAccount();
	}
	
}

Test.java

package com.imooc.bank;

public class Test {

	public static void main(String[] args) {
		// 创建帐户,给定余额为1000
		Bank bank=new Bank("1001",1000);
		//创建线程对象
		SaveAccount sa=new SaveAccount(bank);
		DrawAccount da=new DrawAccount(bank);
		Thread save=new Thread(sa);
		Thread draw=new Thread(da);
		save.start();
		draw.start();
		try {
			
			draw.join();
			save.join();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println(bank);
	}

}

运行结果:
在这里插入图片描述注意:两个线程线程同时运行期间,比如在进行存款的时候,正好运行到

balance += 100;

然后存款线程随时可能停止,然后被取款线程取得了CPU使用权,开始了运行取款的代码,然而存款操作只执行到一半尚未完成存款操作,又开始了取款操作改变了账号的金额,这样子 数据便会混乱 发生脏读等现象。

解决方法:
在这里插入图片描述在这里插入图片描述使用了synchronized的方法 那么在这个方法执行完之前,其他线程是不允许将其打断的。
实现方式案例:
在这里插入图片描述在这里插入图片描述
线程间通信问题:在这里插入图片描述案例:
Consumer.java

package com.imooc.queue;

public class Consumer implements Runnable{
	Queue queue;
	Consumer(Queue queue){
		this.queue=queue;
	}

	@Override
	public void run() {
		while(true){
			queue.get();
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	
}

Producer.java

package com.imooc.queue;

public class Producer implements Runnable{
	Queue queue;
	Producer(Queue queue){
		this.queue=queue;
	}

	@Override
	public void run() {
		int i=0;
		while(true){
			queue.set(i++);
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
	}

}

Queue.java

package com.imooc.queue;

public class Queue {
	private int n;
	
	public synchronized int get() {
			try {
				wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		
		System.out.println("消费:"+n);
		return n;
	}

	public synchronized void set(int n) {
			try {
				wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		
		System.out.println("生产:"+n);
		this.n = n;
	}
	
}

运行结果:
在这里插入图片描述
运行会出现上图的情况,并没有我们想要的 生产一个,便消费一个的效果。
可以运用下图的方法来解决 红框为增加的代码
在这里插入图片描述 在这里插入图片描述在这里插入图片描述
比如 当flag为flase的时候 即当容器当中没有数据的时候 是不能进行消费的 get方法需要进入等待状态。
当flag为ture的时候是不能进行生产的 set方法则进入等待状态。

当线程进入等待的时候,不能全部线程都进入等待,不然会造成死锁。这时在结束之前唤醒所有线程。之所以唤醒所有线程是因为在线程多的情况下不确定哪条线程是需要执行的,全部唤醒通过flag值来决定执行哪个线程。

		notifyAll();//唤醒所有处于等待的线程,使他们结束等待。

总结:
使用第二种方法比较多,因为JAVA不允许多继承。
在这里插入图片描述在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值