一、线程基础
1)概念:程序、进程、线程
程序:通过编程语言编写的一组指令集合
进程:正在运行的程序
线程:进程执行中的执行基本单元
关系:
程序和进程:1:0…n
进程和线程:1:1…n
注:一个进程一定会有一个线程,即main方法
2)线程实现方式
i. 自定义一个类,来extends继承Thread,重写run方法,并构造当前类的对象,通过调用start方法启动
例子:
public class A extends Thread{
public static void main(String[] args) {
A a = new A();
a.start();
}
public void run() {
System.out.println("A");
}
}
ii. 自定义一个类,来实现Runnable接口,重写run方法,并构造当前类对象,再包装秤Thread对象,最后再调用start方法启动
例子:
public class A implements Runnable{
public static void main(String[] args) {
A a = new A();
new Thread(a).start();
}
public void run() {
System.out.println("A");
}
}
iii. 匿名内部类Thread类的方式启动
例如:
public static void main(String[] args) {
new Thread(){
public void run() {
System.out.println("A");
};
}.start();
}
iv. 这三种写法如何做选择?
1. 当当前类已经继承(extends)了一个类了,但是还需要多线程,则只能选择用Runnable
2. 当不需要再继承其他类的时候,毫不犹豫选择继承Thread
3. 线程逻辑很简单的,可以选择用匿名内部类方式做
3)多线程使用场景:程序中出现死循环的时候,后面的代码将永远不会被执行,这时候选择使用多线程,使代码不会因为阻塞无法继续执行。
二、线程同步
案例:银行账户余额处理
张三和李四:是两夫妻
事情:他们在中国银行开了一个户头,张三拿了银行卡,李四拿了存着,存了5000块进去了
发生:某一条两个人没商量情况下,张拿着银行卡去了ATM机上准备去3000,正在这个时候,李四她也拿着存着,去柜台取钱,准备取4000
案例模拟代码:
package com.huaxin.Account;
//账户类
public class Account {
public static void main(String[] args) {
//创建账户对象
Account account = new Account(5000);
//创建两个用户对象
People zhangsan = new People(account, "ATM", 3000);
People lisi = new People(account, "柜台", 4000);
zhangsan.start();
lisi.start();
}
public int count;//余额
private int cash;//取现金额
//构造函数
public Account(int count){
this.count = count;
}
//在方法名前使用同步锁关键字,使该方法不会被多个线程同时调用。
public synchronized int getCash(int cash){
if(cash>count){
return -1;
}
try {
Thread.sleep(100);//线程休眠
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
count = count - cash;
return count;
}
}
package com.huaxin.Account;
//用户类
public class People extends Thread{
//属性
private Account account;
private String way ;//取款方式
private int cash;
//构造函数
public People(Account account , String way, int cash){
this.account = account;
this.way = way;
this.cash = cash;
}
@Override
public void run() {
int result = account.getCash(cash);
if(result <0){
System.out.println("通过"+way+"方式取款失败,欲取款金额为"+cash+",余额为"+account.count);
}else{
System.out.println("通过"+way+"方式取款成功,取款金额为"+cash+",余额为"+result);
}
}
}
运行结果:
通过ATM方式取款成功,取款金额为3000,余额为2000
通过柜台方式取款失败,欲取款金额为4000,余额为2000
注意:如果不使用同步锁关键字,将可能当账户中一个人将钱取出而余额未修改时,另一个人从中取钱,导致能超额取钱。
Synchronized:同步锁关键字
1.可以锁住方法
如上案例
2.可以锁住指定的某个代码块
当线程想执行同步代码块的时候,如果这个代码块已经正在其他线程操作,则会阻塞
二、线程通信:Wait...notify
生产消费线程模型:
生产者---容器空时生产--->容器----容器有产品时消费-->消费者
生产者和消费者共同对同一个容器进行不同操作,两者之间需要一个协同过程(wait...notify方式实现)
Notify通知wait的线程的时候(多个wait机制同时执行的时候),注意,是随机通知的
注意:wait和notify这两个方法一定要在同步关键字区域中使用
三、线程池
1)线程的生命周期:某个线程对象由生到死的整个周期过程
2)线程在整个生命周期过程中,是不能够重复调用start来启动。