`
T240178168
  • 浏览: 365606 次
  • 性别: Icon_minigender_1
社区版块
存档分类
最新评论

synchronized关键字、Callable以及线程池

    博客分类:
  • java
阅读更多
Synchronized关键字
从1.0版本开始,Java中的每一个对象都有一个内部锁。
如果一个方法用synchronized关键字生命,那么对象的锁将保护整个方法。也就是说,要调用该方法,线程必须获得内部的对象锁。

换句话说:
public synchronized void method(){
method body
}
等价于
public void method(){
this.intrinsicLock.lock();
try{
method body
}

finally{ this.intrinsicLock.unlock();}
}

必须了解每一个对象有一个内部锁,并且该锁有一个内部条件。由锁来管理那些试图进入synchronized方法的线程,由条件来管理那些调用wait的线程。


将静态方法声明为synchronized也是合法的。如果调用这种方法,该方法获得这个类的内部锁。(注:原文里是“获得类对象的内部锁”,为了避免出现理解误差,此处改为“类的内部锁”)
例如:如果Bank类有一个静态同步的方法,那么该方法被调用时,Bank.class
的锁被锁住。因此,没有其他线程可以调用同一个类的这个或任何其他的同步静态方法。

个人备注:关键在于区别成员方法和类方法的区别。
synchronized的4种用法
1.      方法声明时使用,线程获得的是成员锁.
2.      对某一代码块使用,synchronized后跟括号,括号里是变量,线程获得的是成员锁.
3.synchronized后面括号里是一对象,此时,线程获得的是对象锁.
4.synchronized后面括号里是类,此时,线程获得的是对象锁.

一、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。
二、然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。
三、尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。
四、第三个例子同样适用其它同步代码块。也就是说,当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。
五、以上规则对其它对象锁同样适用.



Runnable封装一个异步运行的任务,可以把它想象成为一个没有参数和返回值得异步方法。

Callable和 Runnable 类似,但是有返回值。
Callable接口是一个参数化的类型,只有一个方法call。
public interface Callable<V>{
V call() throws Exception;
}

类型参数是返回值的类型。例如Callable<Integer>表示一个最终返回Integer对象的异步计算。





Future保存异步计算的结果,可以启动一个计算,将Future对象交给某个线程,然后忘掉它。Future对象的所有者在结果计算好之后就可以获得它。

public interface Future<V>{
V  get() throws …;
方法被阻塞,直到计算完成。

V  get(lont timeout, TimeUnit unit) throws …;
如果在计算完成之前,第二个方法的调用超时,抛出TimeoutException异常。
如果运行计算的线程被中断,则两个get方法都将抛出InterruptedException。

如果计算已经完成,那么get方法立即返回。

void cancel(boolean mayInterrupt);
使用该方法取消该计算,如果计算还未开始,它被取消且不再开始。
如果计算处于运行之中,那么如果参数为true,它就被中断。

boolean isCancelled();如果在任务正常完成前将其取消,则返回true。
boolean isDone();如果在任务已完成,则返回true。
}

public class FutureTask<V>
extends Object
implements Future<V>, Runnable

FutureTask 包装器是一种非常方便的机制,可以将Callable转换成Future 和 Runnable,它同时实现二者的接口


FutureTask(Callable<V> callable)
          创建一个 FutureTask,一旦运行就执行给定的 Callable。   
FutureTask(Runnable runnable, V result)
          创建一个 FutureTask,一旦运行就执行给定的 Runnable,并安排成功完成时 get 返回给定的结果 。


例如:

Callable<Integer> myCall = ……..;
FutureTask<Integer> task = new FutureTask<Integer>(myCall);
Thread t = new Thread(task);//  在这里是一个Runnable
t.start();
….
Integer result = task.get(); //在这里是一个Future



构建一个新的线程是有一定代价的,因为涉及与操作系统的交互。如果程序中创建了大量的生命期很短的线程,应该使用线程池(thread pool).

一个线程池中包含许多准备运行的空闲线程,将Runnable对象交给线程池,就会有一个线程调用run方法。当run方法退出时,线程不会死亡,而是在池中准备为下一个请求提供服务。
另一个使用线程池的理由是减少并发线程的数目。创建大量线程会大大降低性能甚至使虚拟机崩溃。如果有一个会创建许多线程的算法,应该使用一个线程数“固定的”线程池以限制并发线程的总数。

java.util.concurrent
接口 Executor
所有已知子接口:
ExecutorService, ScheduledExecutorService
所有已知实现类:
AbstractExecutorService, ScheduledThreadPoolExecutor, ThreadPoolExecutor


执行器类(Executor)类有许多静态工厂方法用来构建线程池。java.util.concurrent.Executors
public class Executorsextends Object

ExecutorService  newCachedThreadPool()
返回一个带缓存的线程池,该池在必要时创建新线程;空闲线程会被保留60秒

ExecutorService  newFixedThreadPool(int size)
返回一个线程池,该池包含固定数量的线程;空闲线程会一支被保留

ExecutorService  newSingleThreadExecutor
只有一个线程的“池”,该线程顺序执行每一个提交的任务

这三个方法返回实现了ExecutorService接口的ThreadPoolExecutor类的对象。







Java.util.concurrent.ExecutorService
可用下面的方法之一将一个Runnable对象或Callable对象提交给ExecutorService:

Future<?> submit(Runnable task)
返回一个Future<?>可以使用这样的一个对象来调用isDone、cancel或isCancelled。但是,get方法在完成的时候只是简单的返回null。

Future<T> submit(Runnable task, T result)
返回的Future<T>的get方法在完成的时候返回指定的result对象。

Future<T> submit(Callable<T>  task)
返回的Future对象将在计算结果准备好的时候得到它。

sutdown()
当用完一个线程池的时候,调用shutdown()方法方法启动该池的关闭序列,被关闭的执行器不再接受新的任务。当所有任务都完成以后,线程池中的线程死亡。

shutdownNow()
该方法取消尚未开始的的所有任务并试图中断正在运行的线程。


下面总结在使用线程池时应该做的事:
调用Executors类中静态的方法 newCachedThreadPool或..
调用submit提交Runnable 或Callable对象
如果想要取消一个任务,或如果提交Callable对象,那就需要保存好返回的Future对象
当不需要提交任何任务时,调用shutdown。





补充:
ScheduleExecutorService  newScheduledThreadPool(int size)
用于预定执行而构建的固定线程池,替代java.util.Timer ( Timer用于安排以后
在后台线程中执行的任务。可安排任务执行一次,或者定期重复执行。)

ScheduleExecutorService  newSingleThreadScheduleExecutor()用于预定执行而构建的单线程“池”
分享到:
评论

相关推荐

    21-多线程和线程同步1

    synchronized 关键字是 Java 中的一个关键字,用于声明同步方法或同步块。synchronized 关键字可以确保在同一时刻只有一个线程可以访问共享资源。 Lock 接口 Lock 接口是 Java 中的一个接口,提供了 lock() 方法和...

    多线程异常处理.pdf

    在探讨多线程异常处理之前,首先要了解Java中的线程模型以及异常处理的基本概念。...程序员需要根据具体情况合理地使用try-catch-finally语句以及synchronized关键字,并在必要时对线程池中任务的异常进行监控与处理。

    个人总结40个Java多线程面试问题和答案

    synchronized关键字可以用来修饰方法或代码块,确保在同一个时刻只有一个线程可以访问该资源。 9. deadlock是什么? deadlock是多线程编程中的一种错误,发生在两个或多个线程之间的资源竞争问题。deadlock可能会...

    java多线程,对多线程,线程池进行封装,方便使用

    Java提供了synchronized关键字、Lock接口(如ReentrantLock)以及各种并发容器(如ConcurrentHashMap)来保证线程安全。 10. **线程池的最佳实践** - 核心线程数应根据系统资源和业务需求设定,一般可设为CPU核心...

    基于线程池的Java多线程应用技术.pdf

    Java提供了两种方式实现线程同步机制,分别是使用synchronized关键字和java.util.concurrent.locks.Lock接口。 线程池的应用: 线程池技术可以应用于Web服务系统中,控制服务器系统的最大并发数与最多处理的任务数...

    Java并发编程面试题目

    在Java程序中,创建线程有四种方式:继承Thread类、实现Runnable接口、使用Callable接口和使用线程池。其中,继承Thread类和实现Runnable接口是最常用的两种方式。 线程的生命周期包括五种基本状态:新建状态、就绪...

    深入理解高并发编程-Java线程池核心技术

    为了确保特定线程的执行顺序,我们可以使用synchronized关键字进行同步控制,或者使用Lock接口提供的锁机制。 Java中的Callable接口类似于Runnable,但Callable可以有返回值和抛出异常。Future接口用于表示Callable...

    MultiThread_并发_java_线程池_

    2. 同步与互斥:为了保证数据的一致性和完整性,Java提供了多种同步机制,如synchronized关键字、wait()、notify()和notifyAll()方法,以及Lock接口(如ReentrantLock)和Condition接口。 二、Java多线程实现 1. ...

    Java并发编程面试题

    在Java程序中,多线程的运行安全可以通过使用synchronized关键字、Lock类、volatile关键字、CAS操作等实现。同时,Java也提供了线程池、Executor框架等机制来管理线程的创建和执行。 下面是Java并发编程面试题的...

    java多线程、并发及线程池介绍收藏的几篇文档

    - 同步机制:Java提供了`synchronized`关键字和`volatile`关键字来处理线程间的数据共享问题,避免数据不一致。 2. **Java 多线程与并发编程总结** - 并发编程是多线程的一种高级形式,它涉及到如何管理多个线程...

    Java多线程实现.pdf

    另一个关键概念是ReentrantLock,这是一种可重入的互斥锁,它提供了与synchronized关键字类似的功能。ReentrantLock比synchronized提供了更灵活的操作,包括尝试非阻塞地获取锁、可中断地获取锁以及超时获取锁等。...

    mThread.zip

    Java提供了synchronized关键字以及Lock接口来实现线程同步,确保在特定时刻只有一个线程能访问共享资源。 接下来,我们聊聊线程池。线程池是多线程编程中的高效工具,它可以预先创建一定数量的线程,避免频繁地创建...

    JAVA 写的SOCKET线程池

    8. **并发控制**:在多线程环境下,使用`synchronized`关键字、Locks(如ReentrantLock)进行同步控制,防止数据竞争问题。 9. **异常处理**:在多线程环境中,正确处理异常,避免因单个线程异常导致整个程序崩溃。...

    JAVA并发编程实践-中文-高清-带书签-完整版

    接着,作者探讨了高级并发工具的使用,这些工具能够帮助开发者更有效地管理和协调并发任务,比如使用Future和Callable接口来处理异步计算结果,以及使用ExecutorService进行线程池管理。 书中还深入讨论了并发集合...

    个人总结的深入java多线程开发

    看完《think in java》多线程章节,自己写的多线程文档,还结合了其他的相关网络资料。 线程 一. 线程池 1)为什么要使用线程池 2 2)一个具有线程池的工作队列 3 ...1)ReentrantLock和synchronized关键字的区别 41

    Java中的多线程共15页.pdf.zip

    Java提供了多种同步工具,如synchronized关键字、wait()、notify()和notifyAll()方法,以及Lock接口(如ReentrantLock)和Condition接口。synchronized关键字可以保证在同一时刻只有一个线程访问特定的代码块,防止...

    百度Java面试题 前200页精选(中)

    此外,还可以使用Callable和FutureTask以及线程池等高级技术。 #### 线程安全与同步 线程安全是指当多个线程访问某个类(对象或方法)时,这个类始终能表现出正确的行为。Vector和SimpleDateFormat是线程安全类的...

    Java并发程序设计教程

    Java提供了多种同步机制,包括synchronized关键字、volatile变量、ReentrantLock等。synchronized用于实现线程间的互斥访问,保证共享变量的可见性;volatile确保对变量的修改对所有线程可见,但不保证原子性;而...

Global site tag (gtag.js) - Google Analytics