pubblic final void join() : 让父线程等待子线程结束后才继续运行
pubblic final void join(mills:long) : mills 以毫秒为单位的等待时长
pubblic final void join(mills:long,int nanos) : nanos 要等待的附加纳秒时长
join()的使用场景:
在实际开发中,我们很少会使用thread.join()
在实际使用过程中,我们可以通过join()方法来等待线程执行的结果
我们通过以下伪代码来说明join的使用场景
public void joinDemo(){
//....
Thread t=new Thread(otherService);
t.start();
//....
//其他业务逻辑处理,不需要确定t线程是否执行完
insertData();
//后续的处理,需要依赖t线程的执行结果,可以在这里调用join方法等待t线程执行结束
t.join();
}
Thread.yield():
暂停当前线程,允许其他具有同等优先级的线程获得运行机会
yield 即“谦让”,也是Thread类的方法,它让掉当前线程CPU的时间片,使正在运行中的线程重新变成就绪状态,并重新竞争CPU的调度权。它可能会获取到,也有可能被其他线程获取到
yield和sleep的异同
1、yield,sleep都能暂停当前线程,sleep可以指定具体的休眠时间,而yield则依赖cpu的时间片去划分
2、yield、sleep 两个在暂停过程中,如以及持有锁,则都不会释放锁资源
3、yield不能被中断、而sleep则可以接受中断片
当多个线程对象调用同一个对象的方法时,同一时刻只能有一个线程可以使用资源,其他线程需要等待当前线程将对象资源释放之后才可以继续使用
可以用来修饰一个代码块,也可以用于修饰一个方法。在修饰代码块的时候需要指定当前要锁定的对象,即资源,当修饰方法的时候当前锁对的对象为this,即调用方法的对象。如果用于修饰静态方法,锁定的资源是当前类。
ThreadLocalRandom.current().nexInt(2500);
死锁即有两个或者以上的线程自己占用一部分其他线程需要使用的资源,而且在等待其他占用资源的线程释放资源给自己,形成的一种相互等待的状态
死锁是指两个或两个以上的线程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去,此时称系统处于死锁状态或者系统产生了死锁,这些永远在互相等待的线程称为死锁
可归结为如下两点:
A 竞争资源
系统中的资源可以分成两类
1、可剥夺资源,是指某线程在获得这类资源后,该资源可以再被其他线程或者系统剥夺,cpu和主存均属于可剥夺性资源
2、另一类资源是不可剥夺资源,当系统把这类资源分配给某线程后,再也不能强行收回,只能在线程用完后自行释放,如磁带机,打印机等
产生死锁中的竞争资源之一指的是竞争不可剥夺资源(例如:系统中只有一台打印机,可供线程p1使用,假定p1已占用了打印机,若p2继续要求打印机,打印机将阻塞)
产生死锁中的竞争资源另外一种资源指的是竞争临时资源(临时资源包括硬件中断、信号、消息、缓冲区内的消息等),通常消息通信顺序进行不当,则会产生死锁
注意:在开发中,一定要避免死锁的出现
预防死锁:
1、资源一次性分配:一次性分配所有资源,这样就不会再有请求了:(破话请求条件)
2、只有有一个资源得不到分配,也不给这个进程分配其他的资源:(破话请求保持条件)
3、可剥夺资源:即当某进程获得了部分资源,但得不到其他资源,则释放已占有的i资源(破坏不可剥夺条件)
4、资源有序分配法,系统给每类资源赋予一个编号,每一个进程按编号递增的顺序请求资源,释放则相反(破话环路等待条件)
wait()与notify()都是Object对象上的方法
wait()与notify()都必须放在线程的synchronize块上
notify()是随机唤醒一个在当前对象等待的线程
notifyAll()是唤醒在当前对象上等待的所有线程
生产者专注于生产资源,消费者专注于消费资源;通常情况下,生产者将资源生产完毕之后就开始等待并通知消费者消费资源,消费者开始消费资源,当消费者将资源消费完毕之后开始等待并通知生产者生产资源
资源类型,账号类
import java.util.concurrent.atomic.AtomicInteger;
public class Account {
/**账号余额*/
private AtomicInteger balance=new AtomicInteger(0);
/**
* 挣钱方法
* @param money
*/
private synchronized void inMoney(int money){
if(balance.get() > 15000){
System.out.println("存款终于到15000了,休息一下");
try {
wait(); //让当前线程进行阻塞
} catch (InterruptedException e) {
e.printStackTrace();
}
}
String name=Thread.currentThread().getName();
System.out.println(name+"正在老老实实地挣钱养老婆孩子,上交工资:"+money);
balance.set(balance.get()+money);
notify(); //挣钱后,通知消费者消费 - 通知等待当前对象的线程 进入运行期
}
public synchronized void outMoney(int money){
if (money > balance.get()){
//如果账号余额不够花了,那么肯定要进入等待状态,等老公挣钱
try {
System.out.println("账户余额不足,等待老公挣钱中。。。。。");
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
System.out.println("有钱花了,消费支出:"+money);
balance.set(balance.get()-money);
if (balance.get()<10000){
notify(); //通知生产者挣钱
}
}
}
public AtomicInteger getBalance() {
return balance;
}
public void setBalance(AtomicInteger balance) {
this.balance = balance;
}
}
生产者线程
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
public class ProduceTask implements Runnable {
private Account account;//向账号中挣钱
public ProduceTask(Account account) {
this.account = account;
}
@Override
public void run() {
while (true){
int money= ThreadLocalRandom.current().nextInt(2500)+500;
account.inMoney(money);
try {
TimeUnit.MILLISECONDS.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
消费者线程
import java.util.concurrent.TimeUnit;
public class ConsumerTask implements Runnable {
private Account account;//花钱账号
public ConsumerTask(Account account) {
this.account = account;
}
@Override
public void run() {
while (true){
System.out.println("消费前当前账号余额:"+account.getBalance());
account.outMoney(1500);
System.out.println("消费后当前账号余额:"+account.getBalance());
System.out.println();
try {
TimeUnit.MILLISECONDS.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
测试类
public class Test {
public static void main(String[] args) {
Account account=new Account();
//消费者线程
Thread thread1=new Thread(new ConsumerTask(account),"消费者");
Thread thread2=new Thread(new ProduceTask(account),"生产者");
thread1.start();
thread2.start();
}
}