Java多线程技术杂谈

来源:互联网 发布:firefox json美化插件 编辑:程序博客网 时间:2024/06/16 15:05

实现多线程的三种方式:

1、继承 java.lang.Thread 类 , 然后重写 run 方法 ,通过对象的start方法启动线程。
2、实现 java.lang.Runnable 接口, 然后实现 run 方法,通过 new Thread(对象)的start方法启动线程。
3、实现 java.util.concurrent.Callable 接口,然后实现 call 方法  ,与Runnable的区别是call方法有返回值,可以返回一个自定义对象。而且Callable只能通过线程池的方式启动,如下代码所示:
ExecutorService pool = Executors.newFixedThreadPool(5); //创建线程池MyCallable my = new MyCallable(); Future f = pool.submit(my); Object o = f.get();  //获取call返回的对象

多线程的中断机制

1、join   假设有一个线程对象A,在main方法中(主线程)使用A.join() 就可以中断主线程的执行,等到A线程执行完毕之后才继续执行主线程。需要注意的是在调用join方法前,A线程必须处于可运行状态(即对象已经调用start()方法),否则就不能起到中断的作用。join方法可以接受毫秒为单位的参数,意思是中断作用时间,超过设定的时间之后,如果A线程还没执行完,则A线程会从运行状态切换回可运行状态,主线程将会重新获得执行的机会。
2、yield  该方法为Thread类的静态方法,一个调用yield()方法的线程告诉虚拟机它乐意让其他线程占用自己的位置。这表明该线程没有在做一些紧急的事情。注意,这仅是一个暗示,并不能保证不会产生任何影响。
3、wait /notify/notifyAll     这些方法继承自Object,意思就是所有对象都可以使用,并且这些方法必须在同步代码块/方法中使用(尽管在一般方法中也可以编译通过,但是如果在执行wait或者notify/notifyAll 时程序没有获得相应对象(p.wait()中的p)的锁的时候就会抛出java.lang.IllegalMonitorStateException异常),具体作用在同步章节介绍。
4、sleep 该方法为Thread类的静态方法,可以接受毫秒为单位的参数,意思是中断作用时间,中断过程中不会释放锁,程序处于阻塞状态,直到睡眠时间结束才能继续往下执行。

多线程的同步机制

多线程同步机制针对的是多个线程操作同一个对象(共享对象)时,共享对象的变量会发生不可预知的影响,因为可能存在多个线程同时操作相同变量的情况,所以就需要一些同步机制来应对这种情况,于是乎就产生了如下两种多线程同步的方法:
1、使用 synchronized修饰的方法,只有获得当前对象锁的线程(同一时刻只有一个线程能获得锁)才能执行该对象的同步方法,其它没有获得锁的线程需要等待该线程执行完该方法释放锁以后才能抢夺锁资源去执行该对象的同步方法,所以能够保证同一时刻只有一个线程执行一个同步方法。
public synchronized void print(){    //程序逻辑}

2、使用 synchronized修饰的程序块 ,第一种方法的锁只能是当前对象(this),而使用第二种方式可以使用任意的对象作为锁 。

public void print(){  synchronized(this){       //程序逻辑  }}

锁对象可以调用wait方法来释放当前的锁的对象,线程会进入阻塞状态,只有通过其它拥有该锁的对象调用notify或notifyAll才能唤醒该线程,如果没有线程调用notify/notifyAll 方法则该线程将一直处于阻塞状态 。

锁对象也可以调用notify/notifyAll 方法来唤醒处于wait状态的线程,但是不是调用 notify/notifyAll后就会立即释放锁资源,而是在当前同步方法或者同步代码块执行完才会释放对象锁。

Java中的线程池

1、newFixedThreadPool 创建一个指定工作线程数量的线程池。每当提交一个任务就创建一个工作线程,如果工作线程数量达到线程池初始的最大数,则将提交的任务存入到池队列中,如下代码所示,线程池最多只能允许三个任务线程同时执行。

ExecutorService pool = Executors.newFixedThreadPool(3);for (int i=0; i<10; i++){    pool.execute(new Thread());}

2、newCachedThreadPool 创建一个可缓存的线程池,

1).工作线程的创建数量几乎没有限制(其实也有限制的,数目为Interger. MAX_VALUE), 这样可灵活的往线程池中添加线程。

2).如果长时间没有往线程池中提交任务,即如果工作线程空闲了指定的时间(默认为1分钟),则该工作线程将自动终止。终止后,如果你又提交了新的任务,则线程池重新创建一个工作线程。

ExecutorService pool = Executors.newCachedThreadPool();for (int i=0; i<10; i++){    pool.execute(new Thread());}

3、newSingleThreadExecutor 创建一个单线程化的Executor,即只创建唯一的工作者线程来执行任务,如果这个线程异常结束,会有另一个取代它,保证顺序执行(我觉得这点是它的特色)。
ExecutorService pool = Executors.newSingleThreadExecutor();for (int i=0; i<10; i++){    pool.execute(new Thread());}


4、newScheduleThreadPool 创建一个定长的线程池,而且支持定时的以及周期性的任务执行,类似于Timer。

ScheduledExecutorService pool = Executors.newScheduledThreadPool(3);for (int i=0; i<10; i++){    pool.schedule(new Thread(),3,TimeUnit.SECONDS);}


结合Spring使用线程池

1、ThreadPoolTaskExecutor配置文件

 1 <!-- spring thread pool executor -->            2     <bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor"> 3         <!-- 线程池维护线程的最少数量 --> 4         <property name="corePoolSize" value="5" /> 5         <!-- 允许的空闲时间 --> 6         <property name="keepAliveSeconds" value="200" /> 7         <!-- 线程池维护线程的最大数量 --> 8         <property name="maxPoolSize" value="10" /> 9         <!-- 缓存队列 -->10         <property name="queueCapacity" value="20" />11         <!-- 对拒绝task的处理策略 -->12         <property name="rejectedExecutionHandler">13             <bean class="java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy" />14         </property>15     </bean>


如果此时线程池中的数量小于corePoolSize,即使线程池中的线程都处于空闲状态,也要创建新的线程来处理被添加的任务。

如果此时线程池中的数量等于 corePoolSize,但是缓冲队列 workQueue未满,那么任务被放入缓冲队列。

如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量小于maxPoolSize,建新的线程来处理被添加的任务。

如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量等于maxPoolSize,那么通过handler所指定的策略来处理此任务。也就是:处理任务的优先级为:核心线程corePoolSize、任务队列workQueue、最大线程 maximumPoolSize,如果三者都满了,使用handler处理被拒绝的任务。

当线程池中的线程数量大于corePoolSize时,如果某线程空闲时间超过keepAliveTime,线程将被终止。这样,线程池可以动态的调整池中的线程数。

2、java代码

 1 @RunWith(SpringJUnit4ClassRunner.class) 2 @ContextConfiguration(classes = { MultiThreadConfig.class }) 3 public class MultiThreadTest { 4  5     @Autowired 6     private ThreadPoolTaskExecutor taskExecutor; 7  8     @Autowired 9     private MultiThreadProcessService multiThreadProcessService;10     11     @Test12     public void test() {13         14         int n = 20;15         for (int i = 0; i < n; i++) {16             taskExecutor.execute(new MultiThreadDemo(multiThreadProcessService));17             System.out.println("int i is " + i + ", now threadpool active threads totalnum is " + taskExecutor.getActiveCount());18         }19         20         try {21             System.in.read();22         } catch (IOException e) {23             throw new RuntimeException(e);24         }25     }26 }
 
原创粉丝点击