论坛首页 Java企业应用论坛

说一说java的concurrent包-系列文章

浏览 20695 次
精华帖 (6) :: 良好帖 (5) :: 新手帖 (13) :: 隐藏帖 (0)
作者 正文
   发表时间:2012-02-29  
说一说java的concurrent包6–java里面的线程基础类Thread
http://www.hetaoblog.com/%E8%AF%B4%E4%B8%80%E8%AF%B4java%E7%9A%84concurrent%E5%8C%856%E2%80%93concurrent%E5%8C%85%E4%B9%8B%E5%89%8D%E7%9A%84synchronized%E5%85%B3%E9%94%AE%E5%AD%97/
有网友建议我在介绍concurrent包之前先介绍下jdk1.5之前的多线程知识,这是个相当不错的想法, 这篇就先介绍下Thread类;
Thread类是java中的线程,几乎所有的多线程都在Thread这个类的基础之后展开;
下面介绍这个类的基本用法,Thread类的最基本函数就是run函数
public void run()
简单的说来,基本的创建一个完成自己功能的线程可以继承Thread类,然后override这个run方法, 如下所示
public class ThreadDemo {

	@Test
	public void testThread()
	{
		SimpleThread t = new SimpleThread();
		t.start();

	} 

}
class SimpleThread extends Thread{

	@Override
	public void run() {

		System.out.println( Thread.currentThread().getName() + " is running  ");
	}
}


通常在run方法里面实现自己要做的功能,这里简单的打印了了一句话, 运行结果是
Thread-0 is running
启动一个线程就是new一个自己的Thread对象,然后调用其中的start方法启动这个线程;注意, run()方法运行结束之后这个线程的生命周期就结束了;

上面举的例子是说启动一个线程就去完成一个任务,有的时候我们需要一个线程始终在跑,定期执行一些任务,然后在某个时刻停止这个线程的运行; 那么可以有类似下面的一段代码:

public class ThreadDemo {

	public static void main(String[] args)
	{
		PeriodicalRunningThread t = new PeriodicalRunningThread();
		t.start();

		System.out.println("main thread is going to sleep...");
		try {
			Thread.currentThread().sleep(20 * 1000);

		} catch (InterruptedException e) {

			e.printStackTrace();
		}

		System.out.println(new Date() + " now to stop PeriodicalRunningThread");
		t.setRunning(false);

	}

} 

class PeriodicalRunningThread extends Thread{

	private volatile boolean running = true;

	@Override
	public void run() {

		while(running)
		{
			System.out.println(new Date() + " " + Thread.currentThread().getName() +  " is running " + new Date());

			try {
				Thread.currentThread().sleep(5 * 1000);

			} catch (InterruptedException e) {

				e.printStackTrace();
			}
		}

		System.out.println(new Date() + " " + Thread.currentThread().getName() + " will end");
	}

	public void setRunning(boolean running) {
		this.running = running;
	}

}


这段代码的打印结果是:
main thread is going to sleep…
Wed Feb 29 21:10:39 CST 2012 Thread-0 is running Wed Feb 29 21:10:39 CST 2012
Wed Feb 29 21:10:44 CST 2012 Thread-0 is running Wed Feb 29 21:10:44 CST 2012
Wed Feb 29 21:10:49 CST 2012 Thread-0 is running Wed Feb 29 21:10:49 CST 2012
Wed Feb 29 21:10:54 CST 2012 Thread-0 is running Wed Feb 29 21:10:54 CST 2012
Wed Feb 29 21:10:59 CST 2012 now to stop PeriodicalRunningThread
Wed Feb 29 21:10:59 CST 2012 Thread-0 will end

这里通过一个volatile的boolean值来作为标识表示这个线程的停止;
关于这里的volatile关键字的使用,如有兴趣可以先看这个,核桃博客也会在这个系列的后续文章中对这个关键字做说明
http://www.ibm.com/developerworks/cn/java/j-jtp06197.html

这样,在这个running标识为true的时候,该线程一直在跑,但是完成一段任务后会sleep一段时间,然后继续执行;
0 请登录后投票
   发表时间:2012-03-01  
要是有实际的案例来,而不是将知识点的话,就好了
0 请登录后投票
   发表时间:2012-03-01  
说一说java的concurrent包7–Thread和Runnable
http://www.hetaoblog.com/%E8%AF%B4%E4%B8%80%E8%AF%B4java%E7%9A%84concurrent%E5%8C%857%E2%80%93thread%E5%92%8Crunnable/

这篇还是Thread和Runnable的基础
在前面一篇的代码里面已经介绍了Thread类的其他几个常用的方法,
1. sleep函数,作用是让当前线程sleep一段时间,单位以毫秒计算;
public static void sleep(long millis)
2. 静态方法Thread.currentThread(), 得到当前线程
public static Thread currentThread()
3. getName方法,得到当前线程名称
public final String getName()

这个名称可以在构造Thread的时候传入, 也可以通过setName()方法设置;这个在多线程调试的时候是比较有用的,设置当前线程名,然后在log4j的输出字符串格式里面加入%t,就可以在日志中打印当前线程名称,方便看到当前的日志是从哪里来的;

现在介绍下多线程里面另外一个重要的接口Runnable, 这个接口表示可以被一个线程执行的任务,事实上Thread类也实现了这个Runnable接口;
这个接口只有一个函数, 实现者只要在里面调用代码就可以了
void run()
同时, Thread类有个构造函数是传入一个Runnable实现的;
常用的一个用法就是通过匿名内部类来创建线程执行简单任务,避免写太多的类,外部需要的变量可以通过加final修饰符后传入, 代码例子如下:

	public static void testThreadWithRunnable()
	{
		final String word = "hello,world";
		new Thread(new Runnable() {

			@Override
			public void run() {
				System.out.println(word);

			}
		}).start();
	}

	public static void main(String[] args)
	{
		//periodicalThreadTest();

		testThreadWithRunnable();

	}


上面的代码会打印
hello,world
0 请登录后投票
   发表时间:2012-03-01  
内容不错,就是排版太难看了,话说你的核桃博客广告也忒多了吧...
0 请登录后投票
   发表时间:2012-03-01  
endual 写道
要是有实际的案例来,而不是将知识点的话,就好了


谢谢大家关注,我会先说基础知识和概念,尽量结合简单的代码例子,其实这些代码也是一些实际代码的简单抽象;
后续尽可能的加上实际案例,不过老实说我的实际经验也比较简单,基本就是例子代码的实际场景应用;

当然对于多线程编程我个人的建议是不需要的时候别用,需要的时候简单用,别把简单的问题复杂化,因为这极有可能带来疑难bug或者调试时间
0 请登录后投票
   发表时间:2012-03-01  
learnworld 写道
内容不错,就是排版太难看了,话说你的核桃博客广告也忒多了吧...


哈,博客模板大约是2年以前搞的,我也一直觉得不好:)
改版正在计划中,你可以看下现在的首页,广告略微少了一点;

话说要做个好看/舒服/合理的界面对我有点难度,只能一步一步慢慢改进~
0 请登录后投票
   发表时间:2012-03-01  
用了一段时间了,发个多线程计算的例子吧。
package test;
/**
 * 并行计算数组的和
 * */
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;

public class ConcurrentCalculator {

	private ExecutorService exec;
	private int cpuCoreNumber;
	private List<Future<Long>> tasks = new ArrayList<Future<Long>>();

	// 内部类
	class SumCalculator implements Callable<Long> {
		private int[] numbers;
		private int start;
		private int end;

		public SumCalculator(final int[] numbers, int start, int end) {
			this.numbers = numbers;
			this.start = start;
			this.end = end;
		}

		public Long call() throws Exception {
			Long sum = 0l;
			for (int i = start; i < end; i++) {
				sum += numbers[i];
			}
			return sum;
		}
	}

	public ConcurrentCalculator() {
		cpuCoreNumber = Runtime.getRuntime().availableProcessors();
		exec = Executors.newFixedThreadPool(cpuCoreNumber);
	}

	public Long sum(final int[] numbers) {
		// 根据CPU核心个数拆分任务,创建FutureTask并提交到Executor
		for (int i = 0; i < cpuCoreNumber; i++) {
			int increment = numbers.length / cpuCoreNumber + 1;
			int start = increment * i;
			int end = increment * i + increment;
			if (end > numbers.length)
				end = numbers.length;
			SumCalculator subCalc = new SumCalculator(numbers, start, end);
			FutureTask<Long> task = new FutureTask<Long>(subCalc);
			tasks.add(task);
			if (!exec.isShutdown()) {
				exec.submit(task);
			}
		}
		return getResult();
	}

	/**
	 * 迭代每个只任务,获得部分和,相加返回
	 * 
	 * @return
	 */
	public Long getResult() {
		Long result = 0l;
		for (Future<Long> task : tasks) {
			try {
				// 如果计算未完成则阻塞
				Long subSum = task.get();
				result += subSum;
			} catch (InterruptedException e) {
				e.printStackTrace();
			} catch (ExecutionException e) {
				e.printStackTrace();
			}
		}
		return result;
	}

	public void close() {
		exec.shutdown();
	}
	public static void main(String args[])
	{
		int[] numbers = new int[] { 1, 2, 3, 4 };
		ConcurrentCalculator calc = new ConcurrentCalculator();
		Long sum = calc.sum(numbers);
		System.out.println(sum);
		calc.close();
	}
}


0 请登录后投票
   发表时间:2012-03-01  
楼主几年工作经验?
0 请登录后投票
   发表时间:2012-03-01  
多线程新手请教一下楼主,最后一个例子里,根据cpu拆分起到啥作用?后面的程序有利用cup个数来操作的吗
0 请登录后投票
   发表时间:2012-03-01  
还得请教一下。。
如果单纯地计算数组的话,为啥不直接采用如下方式。。。
Long sum = 0l;
    for(int i=0;i<numbers.length;i++){
    sum += numbers[i];
    }
   
    System.out.println(sum);


因为测了一下,你的例子速度比直接循环算的要慢。。
请教请教。。。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics