java基础 线程理解

来源:互联网 发布:淘宝首页装修视频教程 编辑:程序博客网 时间:2024/04/30 00:44

线程类:Thread类,Runnable类,我们一般定义一个线程有两种方式一种是自定义一个类继承Thread类我们自己扩张run方法,然后生成我们自定义的类的对象。调用start方法启动该线程。另外一种是,我们我们实现Runnable类,扩张其run方法然后生成自定义的类的对象,将其作为Thread类的构造方法的参数,生成Thread对象然后调用生成的类的start方法。


实现:

①.

package com.itheima.study.thread;


//扩张Thread类
public class MyThread extends Thread
{
@Override
public void run()
{
super.run();
for(int i = 0; i < 5; i++)
{
System.out.println("Thread " + i);
try
{
Thread.sleep(500);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
}


②.

package com.itheima.study.thread;


//实现Runnbale类
public class MyRunnable implements Runnable
{


@Override
public void run()
{
for(int i = 5; i > 0; i--)
{
System.out.println("Runnable " + i);
try
{
Thread.sleep(500);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}


}

③.

//测试类

package com.itheima.study.thread;


public class Test
{
public static void main(String[] args)
{
Thread thread1 = new MyThread();
Thread thread2 = new Thread(new MyRunnable());
thread1.start();
thread2.start();
}
}

运行结果:

Thread 0
Runnable 5
Runnable 4
Thread 1
Thread 2
Runnable 3
Thread 3
Runnable 2
Thread 4
Runnable 1

了解了基本的定义和启动一个线程了,以一个经典案列来体现线程。银行卡取钱,取一次钱后,必须存钱。

这其实是一个生产者消费者模式:把银行账户比作一个工厂,当工厂生产了食物过后,消费者必须吃掉食物。然后工厂发现没有食物存在了,又继续生产。一旦有食物存在,工厂就不会继续生产而是等待消费者消费。


Account类:账户类,提供存钱取钱的方法。

FetchMoney类:取钱线程类;操作Account类中的取钱方法。

SaveMoney类:存钱线程类;操作Account类中的存钱方法。

Client类:启动线程。


①.


package com.itheima.study.producer.customer;


//定义银行账户类
public class Account
{
//银行卡余额
private double balance;

// true 表示没有存钱 false则表示已经存钱
private boolean Empty = Boolean.TRUE; 


//判断账户是否有余额
public boolean isEmpty()
{
return Empty;
}


//设置账户余额情况,当存钱或者取钱过后,账户余额情况应该有相应的变化
public void setEmpty(boolean empty)
{
Empty = empty;
}


//初始化账户余额
public Account(double balance)
{
super();
this.balance = balance;
}


//得到账户具体的余额
public double getBalance()
{
return balance;
}


//设置账户的余额,取钱或者存钱过后账户余额都应该减少或者增加
public void setBalance(double balance)
{
this.balance = balance;
}


//操作存钱的方法
public void save(double num)
{


//由于取钱和存钱不能同时发生,防止并发所以要用synchronized关键字修饰
//就是将当前有类加载器加到到虚拟机中的字节码类(Class类)上锁
//class类只有唯一一份,所以就防止了存钱和取钱操作同时被调用
synchronized (Account.class)
{
//如果账户中存在钱
if (!this.Empty)
{
try
{
//让调用该方法的线程处于处于等待状态,去执行取款线程
Account.class.wait();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
//当取款线程执行完成后,执行了Account.class.notify();就将当前的在监视器上等待的线程唤醒,就会执行当前线程下面的代码
// 存款操作
System.out.println(Thread.currentThread().getName() + " 存款前金额为  : " + this.getBalance() + " 本次存款  : " + num);
//存钱过后账户余额增加
this.setBalance(this.getBalance() + num);
System.out.println("存款后金额为  : " + this.getBalance());
System.out.println();
//表示卡上已经有钱
this.Empty = false;
//唤醒取款线程
Account.class.notify();
}
}


public void fetch(double num)
{

//这里的眼里其实就是雨存钱相反。
// 在取款的时候如果发现还没有存款,那么取款的线程等待, 让存款的线程执行
synchronized (Account.class)
{
if (this.Empty)
{
try
{
Account.class.wait();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
//另一个线程执行了Account.class.notify();后就唤醒了当前在等待的线程继续执行wait之后的代码
// 取款操作
//如果卡上余额大于取款金额
if (this.getBalance() >= num)
{
System.out.println(Thread.currentThread().getName() + " 取款前金额为  : " + this.getBalance() + " 本次取款  : " + num);

//账户余额减少
this.setBalance(this.getBalance() - num);

System.out.println("取款后金额为  : " + this.getBalance());
}
else
{
//取款金额大于卡上余额
System.out.println(Thread.currentThread().getName()+ "亲,余额不足 当前余额  : " + this.getBalance() + " 本次取款  : " + num);
}
System.out.println();
//取款后标记为卡上没钱
this.Empty = true;
//唤醒存款线程
Account.class.notify();
}


}


}



②.


package com.itheima.study.producer.customer;


// 取款线程
public class FetchMoney extends Thread
{
//持有一个Account类型的引用
private Account account;
//每次取款的数量
private double number;


//初始化account,number
//name修改线程名字
public FetchMoney(Account account, double number, String name)
{
super(name);
this.account = account;
this.number = number;
}


@Override
public void run()
{
//要执行取款的次数,取款过后线程wait就会执行存款。
for (int i = 0; i < 5; i++)
{
try
{
Thread.sleep(1000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
account.fetch(number);
}
}
}


③.


package com.itheima.study.producer.customer;


// 存款线程
public class SaveMoney extends Thread
{
//持有一个对Account类型的引用
private Account account;
//存钱的数目
private double number;


//初始化accout(初始化为与取款线程中的Account指向同一个地址的引用),number;
//name为修改线程名字
public SaveMoney(Account account, double number, String name)
{
super(name);
this.account = account;
this.number = number;
}


@Override
public void run()
{
//存款的次数,存款过后,wait执行取款
for (int i = 0; i < 5; i++)
{
try
{
Thread.sleep(1000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
account.save(number);
}
}
}


④.


package com.itheima.study.producer.customer;


public class Client {



public static void main(String[] args) {
Account  a = new Account(0);

SaveMoney saveMoney = new SaveMoney(a, 900, "存钱:");
FetchMoney fetchMoney = new FetchMoney(a, 800, "取钱:");

saveMoney.start();
fetchMoney.start();

}
}


运行结果:

存钱: 存款前金额为  : 0.0 本次存款  : 900.0
存款后金额为  : 900.0


取钱: 取款前金额为  : 900.0 本次取款  : 800.0
取款后金额为  : 100.0


存钱: 存款前金额为  : 100.0 本次存款  : 900.0
存款后金额为  : 1000.0


取钱: 取款前金额为  : 1000.0 本次取款  : 800.0
取款后金额为  : 200.0


存钱: 存款前金额为  : 200.0 本次存款  : 900.0
存款后金额为  : 1100.0


取钱: 取款前金额为  : 1100.0 本次取款  : 800.0
取款后金额为  : 300.0


存钱: 存款前金额为  : 300.0 本次存款  : 900.0
存款后金额为  : 1200.0


取钱: 取款前金额为  : 1200.0 本次取款  : 800.0
取款后金额为  : 400.0


存钱: 存款前金额为  : 400.0 本次存款  : 900.0
存款后金额为  : 1300.0


取钱: 取款前金额为  : 1300.0 本次取款  : 800.0
取款后金额为  : 500.0




原创粉丝点击