一个简单的多线程的例子:

package multiThread;

public class BasicThread implements Runnable{

    private int countDown  = 10;
private static int taskCount = 0;
private final int id = taskCount++; public static void main(String [ ] args) {
Thread t = new Thread(new BasicThread());
t.setName("test_thread1");
t.start(); //not t.run(); t.run() will not start a new thread,just exist one thread
System.out.println("i am finished!");
} @Override
public void run() {
while(countDown>=0){
System.out.print("#"+ id + "(" + (countDown>0 ? countDown : "lift off! "+ Thread.currentThread().getName()+ "\r\n") + "),"); 
countDown --;
}
}
}

  运行的结果为:

i am finished!
#0(10),#0(9),#0(8),#0(7),#0(6),#0(5),#0(4),#0(3),#0(2),#0(1),#0(lift off!),

  关于上面的代码有几点说明一下:

  1.final int id = taskCount++,final修饰基本变量时,值是不变的,从结果可以看到,id的值始终为0。

  2.使用t.start()来开启一个线程,而不是t.run(),t.run()还是运行在main方法的线程中,始终只有1个线程。

  3.使用t.setName("test_thread1");是一个好的习惯,方便后续的定位问题。

  使用setDaemon(true)可以将线程设置为后台线程,后台线程有如下的特点:

  1.JVM中只剩下Daemon线程时就会退出,只要还有一个non-Daemon线程存活,JVM就不会退出。Daemon线程可以在做一些后台的服务性工作,例如JVM的gc线程就是一个低优先级的Daemon线程。

  2.线程启动时,默认是non-Daemon的。

  3.setDaemon(true)一定要在start方法之前,否则回报异常。

  4.无法将一个已经启动的non-Daemon线程变为Daemon线程。

  5.Daemon线程中产生的新线程默认将是Daemon的。

  使用Executor来完成多线程,例子如下:

package multiThread;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; public class ExecutorTest { public static void main(String [ ] args) {
ExecutorService exec = Executors.newCachedThreadPool(); //will create one thread for each task
//ExecutorService exec2 = Executors.newFixedThreadPool(5); only eixsts 5 threads,others will wait
//ExecutorService exec3 = Executors.newSingleThreadExecutor();
for(int i=0;i<7;i++){
exec.execute(new BasicThread());
}
//exec.shutdown(); programe will not exit
//exec.execute(new BasicThread()); error
exec.execute(new BasicThread());
exec.execute(new BasicThread());
} }

  所有的线程池在线程可用的情况下,都会去复用已创建的线程,上面的代码运行结果为:

#0(10),#1(10),#0(9),#0(8),#0(7),#0(6),#0(5),#0(4),#0(3),#0(2),#0(1),#3(10),#3(9),#3(8),#3(7),#3(6),#3(5),#3(4),#3(3),#3(2),#3(1),#3(lift off! pool-1-thread-4
),#2(10),#0(lift off! pool-1-thread-1
),#1(9),#1(8),#1(7),#1(6),#1(5),#1(4),#1(3),#1(2),#1(1),#1(lift off! pool-1-thread-2
),#2(9),#2(8),#2(7),#2(6),#2(5),#2(4),#2(3),#2(2),#2(1),#2(lift off! pool-1-thread-3
),#7(10),#7(9),#7(8),#7(7),#7(6),#7(5),#7(4),#7(3),#7(2),#7(1),#6(10),#6(9),#6(8),#6(7),#6(6),#6(5),#6(4),#6(3),#6(2),#6(1),#4(10),#4(9),#4(8),#4(7),#4(6),#8(10),#6(lift off! pool-1-thread-2
),#7(lift off! pool-1-thread-4
),#5(10),#8(9),#8(8),#8(7),#8(6),#8(5),#8(4),#8(3),#4(5),#4(4),#4(3),#4(2),#4(1),#4(lift off! pool-1-thread-5
),#8(2),#8(1),#8(lift off! pool-1-thread-6
),#5(9),#5(8),#5(7),#5(6),#5(5),#5(4),#5(3),#5(2),#5(1),#5(lift off! pool-1-thread-1
),

  上面的例子有一点是需要注意的:

  注释掉exec.shutdown();之后,程序将在所有线程运行完成后一分钟后才结束。如果想要想线程运行完后,程序自动退出,需要加上exec.shutdown();

  exec.shutdown();的作用是为了防止新的任务加入线程队列中。

  如果希望线程在结束时可以带上返回值,可以使用Callable来代替Runnable,如下例: 

package multiThread;

import java.io.UnsupportedEncodingException;
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; public class CallableTest { @SuppressWarnings({ "rawtypes", "unchecked" })
public static void main(String[] args) throws Exception{
ExecutorService es = Executors.newCachedThreadPool();
List<Future> ls = new ArrayList<Future>();
for(int i =0;i<5;i++){
ls.add(es.submit(new RuturnObj(i)));
}
es.shutdown(); //only with es.shutdown(),the program will shut down,unless program will not shut down
for(Future f:ls){
System.out.println(f.get());
} }
} @SuppressWarnings("rawtypes")
class RuturnObj implements Callable{
private int id; RuturnObj(int id){
this.id = id;
} @Override
public Object call() throws Exception {
return "RuturnObj return id: " + id ;
} }

  运行结果为:

RuturnObj return id: 0
RuturnObj return id: 1
RuturnObj return id: 2
RuturnObj return id: 3
RuturnObj return id: 4

  在第一个线程上调用第二个线程的join方法,第一个线程将等待第二个线程完成后再接着执行。如果第一个线程不想等待,可以调用interrupt方法,第一个方法将继续执行,第二个方法将等待执行。

package multiThread;

public class JoinTest {

    public static void main(String [ ] args) {
Sleeper sheep = new Sleeper("sheep"),pig = new Sleeper("pig");
Joiner doc = new Joiner("doc",sheep),gru = new Joiner("gru",pig); gru.interrupt();
}
} class Sleeper extends Thread{
public Sleeper(String name){
super(name);
start();
} public void run(){
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {
System.out.println("Sleeper " + getName() + " was interrupted!");
}
System.out.println("Sleeper " + getName() + " has finished!");
}
} class Joiner extends Thread{
private Sleeper sl;
public Joiner(String name,Sleeper sl){
super(name);
this.sl = sl;
start();
}
public void run(){
try {
sl.join();
}
catch (InterruptedException e) {
System.out.println("Joiner " + getName() + " was interrupted!");
}
System.out.println("Joiner " + getName() + " has finished!");
} }

  输出结果为:

Joiner gru was interrupted!
Joiner gru has finished!
Sleeper sheep has finished!
Sleeper pig has finished!
Joiner doc has finished!

  Java SE5中的concurrent包中的CyclicBarrier使用上比join更为合适。

  下面是一个使用CyclicBarrier的例子,开启了6个线程,模拟统计各省的信息,各省的信息都统计完后再统计全国的信息,如下:

package multiThread;

import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; public class CyclicBarrierTest {
//CountDownLatch: 一个或者是一部分线程 ,等待另外一部线程都完成了,再继续执行
//CyclicBarrier: 所有线程互相等待完成,再执行主任务
//一个是在主任务里面await,一个是在子任务里面await public static void main(String[] args) {
TotalService totalService = new TotalServiceImpl();
CyclicBarrier barrier = new CyclicBarrier(5, new TotalTask(totalService)); List<String> provinceNames = Arrays.asList("北京","上海","广西","四川","黑龙江");
ExecutorService es = Executors.newCachedThreadPool();
for(int i=0;i<provinceNames.size();i++){
es.execute(new BillTask(new BillServiceImpl(), barrier, provinceNames.get(i)));
}
es.shutdown();
}
} /**
* 主任务:汇总任务
*/
class TotalTask implements Runnable {
private TotalService totalService; TotalTask(TotalService totalService) {
this.totalService = totalService;
} public void run() {
// 读取内存中各省的数据汇总,过程略。
System.out.println("=======================================");
System.out.println("开始全国汇总");
totalService.count();
System.out.println("全国数据汇总完毕");
}
} /**
* 子任务:计费任务
*/
class BillTask extends Thread {
// 计费服务
private BillService billService;
private CyclicBarrier barrier;
// 代码,按省代码分类,各省数据库独立。
private String code; BillTask(BillService billService, CyclicBarrier barrier, String code) {
this.billService = billService;
this.barrier = barrier;
this.code = code;
} public void run() {
System.out.println("开始计算--" + code + "省--数据!");
billService.bill(code);
// 把bill方法结果存入内存,如ConcurrentHashMap,vector等,代码略
System.out.println(code + "省已经计算完成,并通知汇总Service!");
try {
// 通知barrier已经完成
barrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
} interface BillService {
public void bill(String code);
} class BillServiceImpl implements BillService { @Override
public void bill(String code) {
Random rd = new Random(47);
int i = rd.nextInt(4000);
try {
Thread.sleep(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} interface TotalService {
public void count();
} class TotalServiceImpl implements TotalService { @Override
public void count() {
Random rd = new Random(47);
int i = rd.nextInt(4000);
try {
Thread.sleep(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

  输出结果为:

开始计算--北京省--数据!
开始计算--广西省--数据!
开始计算--上海省--数据!
开始计算--黑龙江省--数据!
开始计算--四川省--数据!
四川省已经计算完成,并通知汇总Service!
北京省已经计算完成,并通知汇总Service!
黑龙江省已经计算完成,并通知汇总Service!
广西省已经计算完成,并通知汇总Service!
上海省已经计算完成,并通知汇总Service!
=======================================
开始全国汇总
全国数据汇总完毕

  CountDownLatch可以完成与CyclicBarrier类似的功能,CyclicBarrier是可以复用的,CountDownLatch却不可以。

  下面用CountDownLatch模拟项目的开发,只有当每个模块都完成后,项目才完成, 每个模块的用时不同。

package multiThread;

import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
* 模拟项目的开发,只有当每个模块都完成后,项目才完成 每个模块的用时不同
*
*/
public class CountDownLatchTest {
private static final int SIZE = 5; public static void main(String[] args) {
CountDownLatch latch = new CountDownLatch(SIZE);
Random r = new Random(47);
ExecutorService exec = Executors.newCachedThreadPool();
Controller controller = new Controller(latch);
exec.execute(controller);
for (int i = 0; i < SIZE; i++) {
exec.execute(new Module(latch, "模块" + (i + 1), r.nextInt(2000)));
}
exec.shutdown();
}
} class Module implements Runnable {
private CountDownLatch latch;
private String moduleName;
private int time;// 用时 public Module(CountDownLatch latch, String moduleName, int time) {
super();
this.latch = latch;
this.moduleName = moduleName;
this.time = time;
} @Override
public void run() {
try {
work();
latch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
} private void work() throws InterruptedException {
TimeUnit.MILLISECONDS.sleep(time);
System.out.println(moduleName + " 完成,耗时:" + time);
}
} class Controller implements Runnable {
private CountDownLatch latch; public Controller(CountDownLatch latch) {
super();
this.latch = latch;
} @Override
public void run() {
try {
latch.await();
System.out.println("所有模块都完成,任务完成");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

  运行结果为:

模块2 完成,耗时:555
模块3 完成,耗时:693
模块5 完成,耗时:961
模块1 完成,耗时:1258
模块4 完成,耗时:1861
所有模块都完成,任务完成

Java多线程基础(一)的更多相关文章

  1. [转]Java多线程干货系列—(一)Java多线程基础

    Java多线程干货系列—(一)Java多线程基础 字数7618 阅读1875 评论21 喜欢86 前言 多线程并发编程是Java编程中重要的一块内容,也是面试重点覆盖区域,所以学好多线程并发编程对我们 ...

  2. Java多线程基础:进程和线程之由来

    转载: Java多线程基础:进程和线程之由来 在前面,已经介绍了Java的基础知识,现在我们来讨论一点稍微难一点的问题:Java并发编程.当然,Java并发编程涉及到很多方面的内容,不是一朝一夕就能够 ...

  3. Java 多线程——基础知识

    java 多线程 目录: Java 多线程——基础知识 Java 多线程 —— synchronized关键字 java 多线程——一个定时调度的例子 java 多线程——quartz 定时调度的例子 ...

  4. Java多线程--基础概念

    Java多线程--基础概念 必须知道的几个概念 同步和异步 同步方法一旦开始,调用者必须等到方法调用返回后,才能执行后续行为:而异步方法调用,一旦开始,方法调用就立即返回,调用者不用等待就可以继续执行 ...

  5. Java多线程基础知识总结

    2016-07-18 15:40:51 Java 多线程基础 1. 线程和进程 1.1 进程的概念 进程是表示资源分配的基本单位,又是调度运行的基本单位.例如,用户运行自己的程序,系统就创建一个进程, ...

  6. Java基础16:Java多线程基础最全总结

    Java基础16:Java多线程基础最全总结 Java中的线程 Java之父对线程的定义是: 线程是一个独立执行的调用序列,同一个进程的线程在同一时刻共享一些系统资源(比如文件句柄等)也能访问同一个进 ...

  7. 1、Java多线程基础:进程和线程之由来

    Java多线程基础:进程和线程之由来 在前面,已经介绍了Java的基础知识,现在我们来讨论一点稍微难一点的问题:Java并发编程.当然,Java并发编程涉及到很多方面的内容,不是一朝一夕就能够融会贯通 ...

  8. Java 多线程基础(一)基本概念

    Java 多线程基础(一)基本概念 一.并发与并行 1.并发:指两个或多个事件在同一个时间段内发生. 2.并行:指两个或多个事件在同一时刻发生(同时发生). 在操作系统中,安装了多个程序,并发指的是在 ...

  9. Java 多线程基础(三) start() 和 run()

    Java 多线程基础(三) start() 和 run() 通过之前的学习可以看到,创建多线程过程中,最常用的便是 Thread 类中的 start() 方法和线程类的 run() 方法.两个方法都包 ...

  10. Java 多线程基础(四)线程安全

    Java 多线程基础(四)线程安全 在多线程环境下,如果有多个线程在同时运行,而这些线程可能会同时运行这段代码.程序每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线 ...

随机推荐

  1. 洛谷 P1019 单词接龙【经典DFS,温习搜索】

    P1019 单词接龙 题目描述 单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在 ...

  2. Codeforces 626D Jerry's Protest(暴力枚举+概率)

    D. Jerry's Protest time limit per test:2 seconds memory limit per test:256 megabytes input:standard ...

  3. [国嵌攻略][149][Yaffs2文件系统应用]

    嵌入式系统自启动 MTD技术通过把Nand FLash划分成bootloader分区,Linux kernel分区和file system分区来达到自启动的效果. 配置和编译内核 1.配置Linux内 ...

  4. 7系列高速收发器总结 GTP IP核使用篇

    上一篇7系列收发器博文讲解了GTP IP核的基本配置,本文继续分析如何将它使用起来.生成IP核后打开example design,先看看工程中包含的文件结构. 顶层文件下包含了gtp ip核系统顶层文 ...

  5. APIs

    应用程序接口(application programe interfaces)

  6. Struts 2 标签库及使用

    1  Struts 2 基本的标签属性. 1) name:指定表单元素的名称,该属性与Action中定义的属性相对应. 2) value:指定表单元素的值. 3) required:指定表单元素的必填 ...

  7. CPU频率

    CPU频率 CPU频率,就是CPU的时钟频率,简单说是CPU运算时的工作的频率(1秒内发生的同步脉冲数)的简称. 概念 CPU频率,就是CPU的时钟频率,简单说是CPU运算时的工作的频率(1秒内发生的 ...

  8. 修改ncnn的openmp异步处理方法 附C++样例代码

    ncnn刚发布不久,博主在ios下尝试编译. 遇上了openmp的编译问题. 寻找各种解决方案无果,亲自操刀. 采用std::thread 替换 openmp. ncnn项目地址: https://g ...

  9. JVM之对象的创建简要流程

  10. linux_RAID

    什么是RAID? 磁盘阵列,把多个磁盘组合成一个磁盘组,在逻辑上看起来就是一块大的磁盘,提供单个物理磁盘的存储量和更高的存储性能,同时提供不同级别的冗余备份的一种技术,不同的RAID技术对应不同级别 ...