java:多线程基础之Runnable与Thread

java.lang包下有二个非常有用的东西:Runnable接口与Thread类,Thread实现了Runnable接口(可以认为Thread是Runnable的子类),利用它们可以实现最基本的多线程开发。

一、Runnable入门示例

 1 public class RunnableDemo1 {
 2
 3     public static void main(String[] args) {
 4         new Runnable() {
 5             public void run() {
 6                 for (int i = 0; i < 5; i++) {
 7                     try {
 8                         Thread.sleep(100);
 9                     } catch (InterruptedException e) {
10                         e.printStackTrace();
11                     }
12                     System.out.println("r1 -> i=" + i);
13                 }
14
15             }
16         }.run();
17
18         new Runnable() {
19             public void run() {
20                 for (int i = 0; i < 5; i++) {
21                     try {
22                         Thread.sleep(100);
23                     } catch (InterruptedException e) {
24                         e.printStackTrace();
25                     }
26                     System.out.println("r2 -> i=" + i);
27                 }
28             }
29         }.run();
30
31     }
32
33 }

代码很简单,每个线程依次输出0-4这5个数字,运行结果:

r1 -> i=0
r1 -> i=1
r1 -> i=2
r1 -> i=3
r1 -> i=4
r2 -> i=0
r2 -> i=1
r2 -> i=2
r2 -> i=3
r2 -> i=4

二、向Runnable传递参数

实际应用中,线程开始处理前,通常会有一些初始参数,如果要传入参数,可以参考下面的方法,先定义一个Runnable的子类

 1 package com.cnblogs.yjmyzz;
 2
 3 public class MyRunnable implements Runnable{
 4
 5     private String name;
 6     private int max;
 7
 8     public MyRunnable(String name,int max){
 9         this.name = name;
10         this.max = max;
11     }
12
13     public void run() {
14         for (int i = 1; i <= max; i++) {
15             try {
16                 Thread.sleep(5);
17                 System.out.println(name + ".i=" + i);
18             } catch (InterruptedException e) {
19                 e.printStackTrace();
20             }
21         }
22     }
23
24 }

然后这样使用:

 1 package com.cnblogs.yjmyzz;
 2
 3 public class RunnableDemo2 {
 4
 5     public static void main(String[] args) {
 6
 7         new MyRunnable("A", 5).run();
 8
 9         new MyRunnable("B", 5).run();
10     }
11
12 }

运行结果:

A.i=1
A.i=2
A.i=3
A.i=4
A.i=5
B.i=1
B.i=2
B.i=3
B.i=4
B.i=5

三、利用Thread并行处理

刚才的二个例子,相当大家也发现了问题,虽然是有二个线程,但是始终是按顺序执行的,上一个线程处理完成前,下一个线程无法开始,这其实跟同步处理没啥二样,可以通过Thread类改变这种局面:

 1 public class RunnableDemo3 {
 2
 3     public static void main(String[] args) {
 4
 5         Runnable r1 = new MyRunnable("A", 5);
 6         Runnable r2 = new MyRunnable("B", 5);
 7
 8         Thread t1 = new Thread(r1);
 9         Thread t2 = new Thread(r2);
10
11         t1.start();
12         t2.start();
13
14     }
15
16 }

Thread通过start方法,可以让多个线程并行处理,运行结果如下:

B.i=1
A.i=1
B.i=2
A.i=2
B.i=3
A.i=3
B.i=4
A.i=4
B.i=5
A.i=5

从输出结果上看,二个线程已经在并行处理了。

四、通过在线抢购示例理解资源共享

双十一刚过,每到这个时候,通常是狼多肉少,下面的OrderRunnable类模拟这种抢购情况,假设产品数只有10个,抢购的客户却有100个

 1 package com.cnblogs.yjmyzz;
 2
 3 public class OrderRunnable implements Runnable{
 4
 5     String taskName;
 6
 7     public OrderRunnable(String taskName){
 8         this.taskName=taskName;
 9     }
10
11     private int productNum = 10;
12
13     private int customerNum = 100;
14
15     public void run() {
16
17         for (int i = 0; i < customerNum; i++) {
18             if (productNum > 0) {
19                 try {
20                     Thread.sleep(50);
21                 } catch (InterruptedException e) {
22                     e.printStackTrace();
23                 }
24                 System.out.println(taskName + " -> order success!");
25                 productNum -= 1;
26             }
27         }
28
29     }
30
31 }

现在想用二个线程来处理:

 1 package com.cnblogs.yjmyzz;
 2
 3 public class RunnableDemo4 {
 4
 5     public static void main(String[] args) {
 6
 7         Runnable r1 = new OrderRunnable("A");
 8         Runnable r2 = new OrderRunnable("B");
 9
10         new Thread(r1).start();
11         new Thread(r2).start();
12
13     }
14
15 }

运行结果:

A -> order success!
B -> order success!
B -> order success!
A -> order success!
B -> order success!
A -> order success!
A -> order success!
B -> order success!
B -> order success!
A -> order success!
B -> order success!
A -> order success!
A -> order success!
B -> order success!
A -> order success!
B -> order success!
A -> order success!
B -> order success!
A -> order success!
B -> order success!

显然,这个结果不正确,只有10个产品,却生成了20个订单!

正确的做法,让多个Thread共同使用一个Runnable:

 1 package com.cnblogs.yjmyzz;
 2
 3 public class RunnableDemo5 {
 4
 5     public static void main(String[] args) {
 6
 7         Runnable r1 = new OrderRunnable("A");
 8
 9         new Thread(r1).start();
10         new Thread(r1).start();
11
12     }
13
14 }

A -> order success!
A -> order success!
A -> order success!
A -> order success!
A -> order success!
A -> order success!
A -> order success!
A -> order success!
A -> order success!
A -> order success!
A -> order success!

五、ThreadPoolExecutor

如果有大量线程,建议使用线程池管理,下面是ThreadPoolExecutor的示例用法:

 1 package com.cnblogs.yjmyzz;
 2
 3 import java.util.concurrent.ArrayBlockingQueue;
 4 import java.util.concurrent.ThreadPoolExecutor;
 5 import java.util.concurrent.TimeUnit;
 6
 7 public class RunnableDemo7 {
 8
 9     public static void main(String[] args) {
10
11         ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2, 10, 1,
12                 TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(3));
13
14         for (int i = 0; i < 6; i++) {
15             threadPool.execute(new MyRunnable("R"+i, 5));
16         }
17
18     }
19
20 }

运行结果:

R5.i=1
R0.i=1
R1.i=1
R5.i=2
R1.i=2
R0.i=2
R5.i=3
R1.i=3
R0.i=3
R5.i=4
R1.i=4
R0.i=4
R5.i=5
R0.i=5
R1.i=5
R2.i=1
R3.i=1
R4.i=1
R2.i=2
R3.i=2
R4.i=2
R2.i=3
R3.i=3
R4.i=3
R2.i=4
R4.i=4
R3.i=4
R2.i=5
R4.i=5
R3.i=5

agapple在ITeye上有一篇旧贴子,写得很好,推荐大家去看看,特别是下面这张图:

还有这篇 http://jiaguwen123.iteye.com/blog/1017636,也值得参考

时间: 2024-08-25 18:20:46

java:多线程基础之Runnable与Thread的相关文章

Java多线程中的Runnable和Thread

摘要: 在java中可有两种方式实现多线程,一种是继承Thread类,一种是实现Runnable接口:Thread类是在java.lang包中定义的.一个类只要继承了Thread类同时覆写了本类中的run()方法就可以实现多线程操作了,但是一个类只能继承一个父类,这是此方法的局限. 用法: Thread: package org.thread.demo;class MyThread extends Thread{ private String name; public MyThread(Stri

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

Java多线程干货系列—(一)Java多线程基础 字数7618 阅读1875 评论21 喜欢86 前言 多线程并发编程是Java编程中重要的一块内容,也是面试重点覆盖区域,所以学好多线程并发编程对我们来说极其重要,下面跟我一起开启本次的学习之旅吧. 正文 线程与进程 1 线程:进程中负责程序执行的执行单元线程本身依靠程序进行运行线程是程序中的顺序控制流,只能使用分配给程序的资源和环境 2 进程:执行中的程序一个进程至少包含一个线程 3 单线程:程序中只存在一个线程,实际上主方法就是一个主线程 4

Java多线程基础

1. 前言 这篇文章,是对Java多线程编程的基础性介绍. 文章将介绍Java语言为支持多线程编程提供的一些特性.通过这篇文章,您将了解到如何通过Java语言创建一个线程,如何通过内置的锁来实现线程间的同步,如何在线程间进行通信以及线程的中断机制. 2. 什么是线程 线程是操作系统调度的最小单位,在一个进程中,一般至少有一个线程在运行.一个进程中包含的多个线程,在多核处理器中,操作系统可以将多个线程调度到不同的CPU核心上运行,多个线程可以并行运行. 在同一个进程中的多个线程,共享同一个进程空间

Java多线程基础(四)Java传统线程同步通信技术

Java多线程基础(四)Java传统线程同步通信技术 编写代码实现以下功能 子线程循环10次,接着主线程循环100次,接着又回到子线程循环10次,接着再回到主线程又循环100次,如此循环50次. 分析 1)子线程循环10次与主线程循环100次必须是互斥的执行,不能出现交叉,下面代码中通过synchronized关键字实现此要求: 2)子线程与主线程必须交替出现,可以通过线程同步通信技术实现,下面代码中通过bShouldSub变量实现此要求: 其他需要注意的地方 1)其中business变量必须声

java多线程基础知识

1.ThrTest.java 继承Thread类方式 public class ThrTest extends Thread { private String name; public ThrTest() { } public ThrTest(String name) { this.name = name; } public void run() { for (int i = 0; i < 5; i++) { System.out.println(name + "运行 " + i

黑马程序员——java多线程基础知识1

多线程 进程是一个正在执行的程序. cpu在同时执行这些程序,其实是跳跃式的,做快速的切换,时间很短.一个进程可能存在多条路径.迅雷的多路径.每一个进行执行都有一个执行顺序,该顺序是一个执行路径,或这叫一个控制单元.每一个进程至少有一个线程,线程就是进程中的一个独立的控制单元,线程控制进程的执行.jvm启动的时候会有一个进程就叫做java,exe,该进程中至少有一个线程在控制Java程序的执行 ,而且该线程的执行代码在 主函数中.该线程称为主线程.虚拟机至少也有两个线程,一个主线程执行,另一个负

黑马程序员——Java多线程基础知识2

多线程协同 线程间的通讯:我们对资源的操作动作不同,比如说两个卡车一个拉煤一个装煤.但是他们共享了一个资源. 怎么样把这个资源拿出来?怎样把车装满?这个资源当然是一个类,他里面的组成元素就是对象!!现在我们就要有操作对象的思想了,我用对象把这车装满,现在一车装一个对象. 等待唤醒机制: 用的不是sleep是wait.flag标记,这是两人沟通的方式.其实每个标记就要做一次等待或者notify,判断wait,改值notify.线程池.notify唤醒里面的线程,按顺序唤醒.wait和notify必

Java多线程基础总结

背景 Java采用多线程方式实现并行计算,当然并行计算也可以采用多进程方式实现,但是进程切换耗费比较高.而且进程间是隔离的,进程间通信机制比较麻烦,最后JVM本身在操作系统中就一个进程,由它再启动一个进程不太合适,所以Java采用多线程方式实现并行计算. Java从诞生之初,多线程就围绕的是Runnable接口和Thread类展开的.它的底层采用的是c的p线程方式,而且由于多线程的复杂性,p线程的很多概念知识被延伸到了Java层面,这对Java开发者来说算是一个不幸的消息.但是由于多线程的复杂性

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

Java基础16:Java多线程基础最全总结 Java中的线程 Java之父对线程的定义是: 线程是一个独立执行的调用序列,同一个进程的线程在同一时刻共享一些系统资源(比如文件句柄等)也能访问同一个进程所创建的对象资源(内存资源).java.lang.Thread对象负责统计和控制这种行为. 每个程序都至少拥有一个线程-即作为Java虚拟机(JVM)启动参数运行在主类main方法的线程.在Java虚拟机初始化过程中也可能启动其他的后台线程.这种线程的数目和种类因JVM的实现而异.然而所有用户级线