Thread创建一个线程
在想要使用多线程的技术来进行相应的操作的时候: 可以含有以下的方向来进行设计思考! 在创建一个线程的时候通常是创建一个Thread的。 但是这个Thread,是含有多种方式来进行创建操作的。 例如: 直接使用空参数的构造器进行创建操作:
System.out.println("start:" + System.currentTimeMillis());
Thread thread = new Thread();
thread.start();
System.out.println("end:" + System.currentTimeMillis());
这样执行是没有什么效果的。这种情况就是你启动了一个线程,但是这个线程是没有任何事情要干的。
时间是过的飞起的。
但是还有一种方法也是可以进行线程的启动操作的。
使用含有参数方法的构造器进行创建线程:
System.out.println(Thread.currentThread() + "----start:" + System.currentTimeMillis());
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("我正在执行一个任务,不要打扰我!");
System.out.println(Thread.currentThread());
}
});
thread.start();
System.out.println(Thread.currentThread() + "----end:" + System.currentTimeMillis());
这种是开启一个线程让其来进行线程任务的执行操作的。
但是你有没有发现,这种方式有一点缺点的。
这个开启的线程是相当于我要让其进行一些子任务的执行操作的。
Thread进行异步处理
类似于我是老师,我想让学习委员去办公室帮我拿一些书来的。此时学习委员已经出发了,但是我想起来我好像是带了书的。我想要让学习委员不要去办公室拿书了。
若我直接采用这种方式来来进行执行操作的话,是无法满足我的需求的。只要是我叫他去拿书了,她就会喊不回来的。
那是否能对这种方式进行相应的改造操作呢???
java的开发者是给了我们一种实现的方式的。
使用Future的接口满足需求。
相应的解释:
A Future 表示异步计算的结果。提供了用于检查计算是否完成、等待计算完成以及检索计算结果的方法。只有在计算完成后才能使用方法 get 检索结果,必要时会阻止,直到它准备就绪。取消是通过该 cancel 方法执行的。提供了其他方法来确定任务是正常完成还是已取消。计算完成后,无法取消计算。如果为了可取消性而使用 a Future ,但不提供可用的结果,则可以声明表单 Future<?> 的类型,并作为基础任务的结果返回 null 。
public interface Future<V> {
/**
* Attempts to cancel execution of this task. This attempt will
* fail if the task has already completed, has already been cancelled,
* or could not be cancelled for some other reason. If successful,
* and this task has not started when {@code cancel} is called,
* this task should never run. If the task has already started,
* then the {@code mayInterruptIfRunning} parameter determines
* whether the thread executing this task should be interrupted in
* an attempt to stop the task.
*
* <p>After this method returns, subsequent calls to {@link #isDone} will
* always return {@code true}. Subsequent calls to {@link #isCancelled}
* will always return {@code true} if this method returned {@code true}.
*
* @param mayInterruptIfRunning {@code true} if the thread executing this
* task should be interrupted; otherwise, in-progress tasks are allowed
* to complete
* @return {@code false} if the task could not be cancelled,
* typically because it has already completed normally;
* {@code true} otherwise
*/
boolean cancel(boolean mayInterruptIfRunning);
/**
* Returns {@code true} if this task was cancelled before it completed
* normally.
*
* @return {@code true} if this task was cancelled before it completed
*/
boolean isCancelled();
/**
* Returns {@code true} if this task completed.
*
* Completion may be due to normal termination, an exception, or
* cancellation -- in all of these cases, this method will return
* {@code true}.
*
* @return {@code true} if this task completed
*/
boolean isDone();
/**
* Waits if necessary for the computation to complete, and then
* retrieves its result.
*
* @return the computed result
* @throws CancellationException if the computation was cancelled
* @throws ExecutionException if the computation threw an
* exception
* @throws InterruptedException if the current thread was interrupted
* while waiting
*/
V get() throws InterruptedException, ExecutionException;
/**
* Waits if necessary for at most the given time for the computation
* to complete, and then retrieves its result, if available.
*
* @param timeout the maximum time to wait
* @param unit the time unit of the timeout argument
* @return the computed result
* @throws CancellationException if the computation was cancelled
* @throws ExecutionException if the computation threw an
* exception
* @throws InterruptedException if the current thread was interrupted
* while waiting
* @throws TimeoutException if the wait timed out
*/
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
通过这个接口就可以实现相对应的功能操作了。
给予了一个接口想要将其进行实现操作就得要相关的实现类。
登场的就是FutureTask的类进行操作的。
public FutureTask(Runnable runnable, V result) {
this.callable = Executors.callable(runnable, result);
this.state = NEW; // ensure visibility of callable
}
执行一下相关的代码:
FutureTask<String> stringFutureTask = new FutureTask<String>(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("我正在执行一个任务,不要打扰我!");
System.out.println(Thread.currentThread());
}
} , null);
Thread futureThread = new Thread(stringFutureTask);
futureThread.start();
// 是可以满足对一个进行任务的取消工作的
// stringFutureTask.cancel(true);
System.out.println(stringFutureTask.isCancelled());
Thread futureThread1 = new Thread(stringFutureTask);
futureThread1.start();
第二个 futureThread1 是不会执行的。
解释原因:
在Java中,
FutureTask
只能执行一次。当您尝试第二次执行相同的FutureTask
实例时,它不会执行任何操作。这是因为FutureTask
的状态在第一次执行后会改变,它不会重新开始。如果第一个线程(futureThread
)已经开始执行stringFutureTask
,那么第二个线程(futureThread1
)尝试开始相同的stringFutureTask
时,将不会有任何效果,因为FutureTask
的状态已经不是初始状态了。这里是一些关键点:
FutureTask
在执行后会进入完成状态。如果尝试再次执行一个已经完成的
FutureTask
,它不会重新执行。如果需要重新执行任务,您需要创建一个新的
FutureTask
实例。上面相关的例子,已经将一个老师叫学习委员去办公室拿书的例子叫停了。也就是说现在是实现了异步处理的操作。
带有参数的返回线程处理
我现在还有一个需求,是干嘛的呢???我不是喊学习委员去办公室拿书了吗??我想要那个他拿到的书给我手上。这个功能是怎么实现的呢?
也就是含有返回值的相关的例子!!!
JUC给了一个方法,是可以直接将一个Callable的接口传过来的
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}
使用这个接口作为参数传给的FutureTask进行任务的初始化操作。
我们知道Callable接口是有返回值的。那么就可以类似于得到相应的那一本书了!!!
操作实现:
FutureTask<String> stringFutureTask = new FutureTask<String>(new Callable<String>() {
@Override
public String call() throws Exception {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("我正在执行一个任务,不要打扰我!");
return "老师,我拿到书了";
}
});
Thread thread = new Thread(stringFutureTask);
thread.start();
System.out.println(stringFutureTask.get());
将得到的东西进行返回操作。这样的话就可以实现三种基本的功能操作了。