java高并发总结5--java runnable接口的引入以及策略模式在Thread中的使用

1、runnable的职责
2、策略模式在thread中的应用
3、模拟营业大厅叫号机程序

------------------------------------------------------runnable的职责-------------------------------------------------------------------
runnable源码如下:

package java.lang;

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

在很多软文以及一些书籍中,经常会提到,创建线程有两种方式,第一种是构造一个Thread,第二种是实现Runnable接口,这种说法是错误的,最起码不是严谨的,在JDK代表线程的就只有Thread这个类,我们在前面分析过,线程的执行单元就是run方法,你可以通过继承Thread然后重写run方法实现自己的业务逻辑,也可以实现Runnable接口实现自己的业务逻辑,代码如下:

 @Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }

如果构造Thread时传递了runnable,则会执行runnable的run方法。
否则需要重写thread的run方法。

上面代码是Thread run方法的源码,实现线程有两种方法是一种是创建一个Thread一种是实现Runnable接口,这种说法是不严谨的。准确的说应该是,创建线程只有一种方式那就是构造thread类,而实现线程的执行单元则有两种方式,第一种是重写thread的run方法,第二种是实现runnable接口的run方法,并且将runnable实例用作构造Thread的参数。

Thread和runnable之间的关系是怎样的呢?
Thread负责线程本身相关的职责和控制,而runnable则负责逻辑执行单元的部分。

------------------------------------------------------策略模式在thread中的应用-----------------------------------------------------

前面说了,无论是runnable的方法,还是thread类本身的run方法(事实上Thread类也是实现了Runnable的接口)都是想将线程控制本身和业务逻辑的运行分离开来,达到指责分明、功能单一的原则,这一点与GoF设计模式中的策略设计模式很相似,我们来看看什么是策略设计模式,然后再来对比Thread和runnable两者之间的关系。

相信很多人都做过JDBC的开发,线面我们在这里做一个简单的查询操作,只不过是把数据的封装部分抽象成了策略接口

package lambda;

import java.sql.ResultSet;

public interface RowHandler<T> {
	
	T handle(ResultSet rs);
	
}

RowHandler接口只负责对从数据库中查询出来的结果集进行操作,至于最终返回成什么样的数据结构,那就需要你自己去实现,类似于Runnable接口,代码示例如下:

package lambda;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class RecordQuery {
	
	private final Connection con;
	
	public RecordQuery(Connection con) {
		this.con = con;
	}
	
	public <T> T query(RowHandler<T> handler,String sql,Object... params ) throws SQLException {
		
		try(PreparedStatement stmt = con.prepareStatement(sql)){
			int index = 1;
			for(Object param:params) {
				stmt.setObject(index++,param );
			}
			ResultSet res = stmt.executeQuery();
			//自己实现数据的返回格式
			return handler.handle(res);
		}
	}

}

RecordQuery中的query只负责将数据查询出来,然后调用RowHandler进行数据封装,至于将其封装成什么数据结构,那就的看自己怎么处理了,下面我们来看看这样做到底有什么好处?

上面这段代码的好处就是可以用query方法应对任何数据库的查询,返回结构的不同只会因为你传入的RowHandler思维不同而不同,同样RecordQuery只负责数据的获取,而RowHandler则负责数据的加工,职责分明,每个类均功能单一,相信通过简单的示例就已经清楚的了解Thread和Runnable之间的关系了。

注意:重写Thread的run方法和显示Runnable接口的run方法还有一个很重要的不同,那就是Thread类的run方法是不能共享的,也就说A线程不能把B线程的run方法当作自己的执行单元,而使用runnable接口则很容易就能实现这一点,使用同一个runnable的实例(作为参数)构造不同的Thread实例。这样使用起来更为灵活。

------------------------------------------------------模拟营业大厅叫号机程序-------------------------------------------------------
一个简单的小例子随后附上源码。

猜你喜欢

转载自blog.csdn.net/ppwwp/article/details/86759630