1、
线程入门
//构建线程类——方式一,继承Thread类方式。
import java.util.Date;
public class ThreadDemo{
//main方法,程序的入口
public static void main(String[] args){
//定义并实例化外部类对象
ThreadDemo td = new ThreadDemo();
//通过外部类对象来实例化内部类对象
PrintThread pt1 = td.new PrintThread("thread1",1000);
PrintThread pt2 = td.new PrintThread("thread2",3000);
//启动线程1,线程2
pt1.start();
pt2.start();
//通过调用start方法,start方法会去调用run方法启动线程
}
//定义线程类,内部类
class PrintThread extends Thread{
public PrintThread(String name,long sleepTime){
this.name = name;
this.sleepTime = sleepTime;
}
//覆写父类的run方法
@Override
public void run(){
//简单模拟循环
while(true){
try{
//定义并实例化对象
Date date = new Date();
System.out.println("name = "+name+",date = "+date.toString());
//线程休眠
Thread.sleep(sleepTime);
}catch(Exception e){
//出现异常
System.out.println(e);
}
}
}
//线程名称、休眠时间
private String name;
private long sleepTime;
}
}
//这种方式构建线程缺点:java的单继承是个问题。
//构建线程类——方式二,通过实现
Runnable接口
import java.util.Date;
public class PrintDemo2{
public static void main(String[] args){
PrintThread pt1 = new PrintThread();
PrintThread pt2 = new PrintThread();
//实例化线程对象传入Runnable接口实现,并启动线程。
new Thread(pt1).start();
new Thread(pt2).start();
//启动start方法后会去执行run方法
}
//通过实现Runnable接口来定义线程类
static class PrintThread implements Runnable{
public PrintThread(String name,long sleepTime){
this._name = name;
this._sleepTime = sleepTime;
}
public void run(){
while(true){
try{
Date date = new Date();
System.out.println("name = "+_name+",date = "+date);
//线程休眠
Thread.sleep(_sleepTime);
}catch(Exception e){
System.out.println(e);
}
}
}
//定义线程名称、休眠时间
private String _name;
private long _sleepTime;
}
}
2、线程
同步入门
//有问题,待定解决了。
//银行账户并发程序演示
public class BankSynDemo{
//main方法,程序的入口
public static void main(String[] args) throws Exception{
Account[] accounts = new Account[10];
//初始化10个账户对象,金额设置为100f
//totalMoney = 1000f
for(int i=0;i<10;i++){
accounts[i] = new Account("account_"+i,100f);
}
//随机产生一个转账金额数目
Random random = new Random();
float transMoney = 0f;
//构建1000个线程
for(int j=0;j<1000;j++){
transMoney = random.nextFloat();
//编写代码如果写成下面这种方式
//循环一千次,多构建了二千个对象,而达到的效果是一样的。
//Random random = new Random();
//float transMoney = random.nextFloat();
new Thread(new BankTransThread(accounts,transMoney)).start();
}
//查看余额是否正确,在主线程中查看
//main thread.
while(true){
float sum = 0f;
for(int k=0;k<accounts.length;k++){
sum += accounts[k].get_amount();
}
//total money print.
System.out.println("totalMoney = "+sum+"f,thread = "+Thread.currentThread().getName());
}
}
//定义银行账户实例类
static class Account{
//构造方法
public Account(String accountName,float amount){
this._name = accountName;
this._amount = amount;
}
//转入金额,不进行同步处理。
public void income(float addAmount){
if(addAmount>0f){
//进行转入处理
this._amount += addAmount;
System.out.println("add success,addAmount = "+addAmount+",thread = "+Thread.currentThread().getName());
}else{
//转入失败显示,一般采用记录日志方式
//添加金额不满足条件,不进行阻塞,直接不进行操作即可。
System.out.println("add error,addAmount = "+addAmount+",thread = "+Thread.currentThread().getName());
}
}
//转出金额,进行同步处理
public void expend(Account toAccount,float transMoney){
synchronized(Account.class){
//Date date = new Date();
//账户金额变更处理
if(transMoney>0f && this._amount>transMoney){
this._amount -= transMoney; //当前账户减少金额
toAccount.income(transMoney); //转入账户添加金额
System.out.println("expend success,toAccount = "+toAccount.get_name()+",transMoney = "+transMoney+",thread = "+Thread.currentThread().getName());
}else{
//转出失败,一般采用记录日志方式
System.out.println("expend error,toAccount = "+toAccount.get_name()+",transMoney = "+transMoney+",thread = "+Thread.currentThread().getName());
}
//进行唤醒其他所有等待的线程来抢占这个锁对象操作
//this.notifyAll(); 出异常了
}
}
//获取当前账户金额
public float getAmountMoney(){
synchronized(Account.class){
return this._amount;
}
}
//定义账户名称、金额
private String _name;
private float _amount;
public String get_name() {
return _name;
}
public float get_amount() {
return _amount;
}
}
//定义银行转账线程类
static class BankTransThread implements Runnable{
public BankTransThread(Account[] accounts,float transMoney){
this.accounts = accounts;
this.transMoney = transMoney;
}
public void run(){
//转账方法调用,简单模拟,一直在进行转账操作
while(true){
transMoney(this.transMoney);
}
//只转账一次
//transMoney(this.transMoney);
}
//转账方法实现
protected void transMoney(float transMoney){
int size = accounts.length;
//从外部传入处理,不再写死
//float transMoney = 10f; //转账金额为10f
Random random = new Random();
int from = random.nextInt()%size;
int to = random.nextInt()%size;
//处理负数情况
if(from<0) from = -from; //变为正数
if(to<0) to = -to; //变为正数
//进行转账处理
accounts[from].expend(accounts[to],transMoney);
}
private Account[] accounts; //银行账户集合
private float transMoney; //转账金额
}
}
3、并发模型框架设计
//服务提供者,对外提供服务:它通过一个接口对外提供服务。
//客户端调用方,下面简单代码模拟。
//原文链接:http://www.ibm.com/developerworks/cn/java/l-multithreading/#ibm-pcon
//看得奇怪奇怪的文章,先记录下来。主要代码如下:
//服务接口
public interface Service{
public void sayHello();
}
//服务接口实现
public class ServiceImpl implements Service{
public void sayHello(){
System.out.println("hello world.");
}
}
//存在问题:线程并发问题。
//同步调用,造成client阻塞。原因是由于所有的服务调用都是同步的。
//解决方案是改成
异步调用方式,把服务的调用和服务的执行进行分离。
//下面代码演示使用主动对象来封装并发逻辑。
//应用逻辑和并发逻辑的隔离,服务调用和服务执行的隔离。
//定义MethodRequest接口,用来包装调用者的请求。
public interface MethodRequest{
public void call();
}
//定义一个ActiveQueue队列,实现看具体业务场景。
public class ActiveQueue{
private Object lock = new Object(); //锁对象
private Stack<MethodRequest> activeQueue; //请求栈、队列
private final static int SIZE = 20; //栈、队列长度
public ActiveQueue(){
activeQueue = new Stack<MethodRequest>(); //初始化栈、队列对象
}
//请求入栈方法实现
public void enqueue(MethodRequest request) throws Exception{
//线程同步处理
synchronized(lock){
while(activeQueue.size()>SIZE){
lock.wait(); //条件判定,进行阻塞。
}
//将请求放到栈中。
activeQueue.push(request);
lock.notifyAll(); //交出锁对象,让其他线程来抢占这个锁对象。
System.out.println("request input success,thread = "+Thread.currentThread().getName());
}
}
//获取请求出栈方法实现
public MethodRequest dequeue() throws Exception{
synchronized(lock){
while(activeQueue.empty()){
lock.wait();
}
//将请求退出栈中
MethodRequest popRequest = activeQueue.pop();
lock.notifyAll(); //交出锁对象,让其他线程来抢占这个锁对象。
System.out.println("request pop success,thread = "+Thread.currentThread().getName());
return popRequest;
}
}
}
//定义一个ActiveObject类,用来包装并发逻辑。
public class ActiveObject implements Runnable{
private ActiveQueue activeQueue; //方法请求队列
public ActiveObject(){
activeQueue = new ActiveQueue();
}
//将方法请求(request)放到队列中去
public void enqueue(MethodRequest request){
this.activeQueue.enqueue(request);
}
//提取出当前队列中的请求
public MethodRequest dequeue(){
return this.activeQueue.dequeue();
}
public void run(){
while(true){
//调用获取一个request请求
MethodRequest request = this.dequeue();
//处理相关业务逻辑
request.call();
}
}
}
//下面模拟更上一层处理代码
//方法请求的实现类,面向接口编程
public class SayHello implements MethodRequest{
//构造方法,传入service对象参数
public SayHello(Service service){
this.service = service;
}
public void call(){
//调用service的sayHello方法
this.service.sayHello();
}
//引入service对象
private Service service;
}
//定义一个服务代理类,来完成请求的封装、排队功能。
//当然为了做到对client的透明,该类必须实现service接口。
public class ServiceProxy implements Service{
public ServiceProxy(){
//实例化服务实现对象
this.service = new ServiceImpl();
//实例化活动对象
this.activeObject = new ActiveObject();
}
public void sayHello(){
MethodRequest request = new SayHello(this.service);
this.activeObject.enqueue(request); //加入到请求队列中
}
private Service service;
private ActiveObject activeObject;
}
//客户端类
public class Client{
//持有业务层service的引用
private Service service;
//构造方法,参数为service对象
public Client(Service service){
this.service = service;
}
//requestService方法实现
public void requestService(){
this.service.sayHello();
}
//main方法,程序的入口
public static void main(String[] args){
Client clientMain = new Client(new ServiceImpl());
clientMain.sayHello();
}
}
//并发逻辑下的客户端代码如下:
public class ClientMainDemo{
public static void main(String[] args){
Service service = new ServiceProxy();
//1、实例化一个实现serviceimpl对象。 //为什么不直接实例化呢,要用代理服务对象呢。
//2、实例化一个活动对象,用来包装了并发逻辑的处理对象。
Client client = new Client(service);
client.requestService();//调用方法
}
}