java线程的简单例子(Thread and runnable)

原创 2012年03月22日 19:05:01

http://interper56-sohu-com.iteye.com/blog/172303

其实要了解java多线程只需要理解以下几个事情:
1) java.lang.Thraed类
2) java.lang.Runnable接口
3) synchronized关键字
4) wait(),.notify(), notifyAll();

That’s all.

[java.util.Thread类]
Jdk的线程实现类,只要继承这个类那么我们就可以实现自己的线程。
如果你想要继承这个类,主要需要重载run方法。

例如:
Java代码 复制代码 收藏代码
  1. Pubilc class MyThread {   
  2.     Pubilc MyThread() {   
  3.         Super();   
  4.     }   
  5.   
  6.     Public void run() {   
  7.         System.out.println(“Hello world”);   
  8.     }   
  9. }  


当你要是用它的时候
Java代码 复制代码 收藏代码
  1. Publi class ThreadTest {   
  2.     Public static void main(String[] args)  {   
  3.         MyThread app = new MyThread();   
  4.         App.start();   
  5.     }   
  6. }  


当你运行这个方法的时候,就会打出Hello world.

[java.lang.Runnable接口]
因为继承Thread类就无法继承别的你想要变为线程的类,
所以java.lang.Runnable接口可以实现你的愿望

那么看下面的例子:
食物类:
Java代码 复制代码 收藏代码
  1. public class Food {   
  2.     private int foodNum = 0;   
  3.   
  4.     public Food(int foodNum) {   
  5.         this.foodNum = foodNum;   
  6.     }   
  7.        
  8.     public void setFoodNum(int foodNum) {   
  9.         this.foodNum = foodNum;   
  10.     }   
  11.        
  12.     public int getFoodNum() {   
  13.         return this.foodNum;   
  14.     }   
  15. }  

消费者类:
Java代码 复制代码 收藏代码
  1. public class Customer {   
  2.     private String name = "";   
  3.   
  4.     public Customer(String name) {   
  5.         this.setName(name);   
  6.     }   
  7.   
  8.     protected void setName(String name) {   
  9.         this.name = name;   
  10.     }   
  11.   
  12.     protected String getName() {   
  13.         return this.name;   
  14.     }   
  15. }  

消费者线程类:
Java代码 复制代码 收藏代码
  1. public class CustomerThread extends Customer implements Runnable {   
  2.   
  3.     private Food food = null;   
  4.   
  5.     public CustomerThread(Food food) {   
  6.         super("Customer");   
  7.         this.food = food;   
  8.     }   
  9.   
  10.     public void run() {   
  11.         this.consume();   
  12.     }   
  13.        
  14.     public void startConsume() {   
  15.         Thread thread = new Thread(this);   
  16.         thread.start();   
  17.     }   
  18.   
  19.     private void consume() {   
  20.         int num = this.food.getFoodNum();   
  21.         num++;   
  22.         this.food.setFoodNum(num);   
  23.         System.out.println(this.getName() + " " + "consume food");   
  24.     }   
  25. }  

生产者类:
Java代码 复制代码 收藏代码
  1. public class Productor {   
  2.     private String name = "";   
  3.   
  4.     public Productor(String name) {   
  5.         this.name = name;   
  6.     }   
  7.   
  8.     protected void setName(String name) {   
  9.         this.name = name;   
  10.     }   
  11.   
  12.     protected String getName() {   
  13.         return this.name;   
  14.     }   
  15. }  

消费者类:
Java代码 复制代码 收藏代码
  1. public class ProductorThread extends Productor implements Runnable {   
  2.   
  3.     private Food food = null;   
  4.        
  5.     public ProductorThread(Food food) {   
  6.         super("Productor");   
  7.         this.food = food;   
  8.     }   
  9.   
  10.        
  11.     public void run() {   
  12.         this.increase();   
  13.     }   
  14.        
  15.     public void startIncrease() {   
  16.         Thread thread = new Thread(this);   
  17.         thread.start();   
  18.     }   
  19.   
  20.     private void increase() {   
  21.         int num = this.food.getFoodNum();   
  22.         num--;   
  23.         this.food.setFoodNum(num);   
  24.         System.out.println(this.getName() + " " + "increase food");   
  25.     }   
  26. }  


测试类:
Java代码 复制代码 收藏代码
  1. public class MainTest {   
  2.     public static void main(String[] args) {   
  3.         Food food = new Food(0);   
  4.         ProductorThread productor = new ProductorThread(food);   
  5.         productor.startIncrease();   
  6.         CustomerThread customer = new CustomerThread(food);   
  7.         customer.startConsume();   
  8.     }   
  9. }  


上面代码主要模拟了生产者和消费者生产食物,消费食物的过程,
这里面先让生产者生产了1个食物,然后让消费者消费了1个食物。

主要是想说明我们自己实现的Runnable接口的类必须借助Thread类
才可以把它变成一个线程,如果不借助Thread类,即使我们实现了run()方法,
这个类的对象也不会是一个线程。
说白了,就是用Thread(Runnable thread)这个构造方法把我们实现的Runnable
街口的类传入,然后通过Thread的start方法,来调用我们的run方法,其实
我们实现的Runnable接口的类要想变为线程,是要通过Thread这个载体来实现。

但是上面的实现存在一个问题,我们并不能保证同一时间内只有一个
CustomerThread线程在消费,不能保证在同一时间只有一个ProductorThread
线程在生产。

所以我们引入了synchronized关键字

[synchronized关键字]
通过在CustomerThraed的consume方法和ProductorThread的increase
方法前面加入synchronized关键字就可以解决上面所说的问题。
改动后的方法为:
Java代码 复制代码 收藏代码
  1. private synchronized void consume() {   
  2.     int num = this.food.getFoodNum();   
  3.     num++;   
  4.     this.food.setFoodNum(num);   
  5.     System.out.println(this.getName() + " " + "consume food");   
  6. }   
  7. private synchronized void increase() {   
  8.     int num = this.food.getFoodNum();   
  9.     num--;   
  10.     this.food.setFoodNum(num);   
  11.     System.out.println(this.getName() + " " + "increase food");   
  12. }  

那么synchronized关键字到底是干什么用的呢?

就是进入到synchronized关键字所包含的代码块的线程
都会尝试获得对象的锁,等拿到对象的锁后就可以进去执行代码,
如果得不到,就在那里阻塞,等待其它线程释放锁,那么怎么用呢?

1)在方法前用synchronized关键字,如下:
Java代码 复制代码 收藏代码
  1. private synchronized void consume() {   
  2.     int num = this.food.getFoodNum();   
  3.     num++;   
  4.     this.food.setFoodNum(num);   
  5.     System.out.println(this.getName() + " " + "consume food");   
  6. }  


当线程进入到这个方法的时候,这个线程就会获得这个方法所在对象的锁,
那么其他的进程想要进入这个方法,首先尝试去获得这个方法所在对象的锁,
但是已经被前一个线程霸占了,所只能等待,当前一个线程把这段代码执行
完毕,那么后来的线程就可以获得这个对象锁了,当然它进去后又会把后面的
线程阻塞在外面等待。
这种方法等同于:
Java代码 复制代码 收藏代码
  1. private void consume() {   
  2.     synchronized(this) {   
  3.         int num = this.food.getFoodNum();   
  4.         num++;   
  5.         this.food.setFoodNum(num);   
  6.         System.out.println(this.getName() + " " + "consume food");   
  7.     }   
  8. }  


但是这种方法我们把整个对象都锁住了,其他线程想要执行这个类中的其它用
Synchronized方法声明的方法都不可以了,因为想要进入其它的synchronized
方法也要先获得这个对象的锁,所以这种方法比较霸道,我们不建议这么做,
所以出现了第二种方法。
2)声明一个临时的对象,让进入同一个方法的线程去获得这个临时对象的锁,
  那么获得这个临时对象的锁,并不是整个对象的锁,所以并不会锁住整个对象,
  当然也就避免了上面第一种所遇到的问题:
Java代码 复制代码 收藏代码
  1. private void consume() {   
  2.     Object lock = new Object();   
  3.     synchronized(lock) {   
  4.         int num = this.food.getFoodNum();   
  5.         num++;   
  6.         this.food.setFoodNum(num);   
  7.         System.out.println(this.getName() + " " + "consume food");   
  8.     }   
  9. }  

Obj是一个临时的对象,当多个线程进入到这个方法的时候都会尝试去获得这个
Obj对象的锁,谁先获得,谁就可以继续执行,否则阻塞在外面,等待前一个进程
结束执行synchronized内的代码,出了synchronized包含的代码块之后,
会马上自动释放对这个obj对象的锁。

[wait(), notify()和notifyAll()]
其实采用了上面的synchronized关键字之后,上面的代码还是有问题,
什么问题?
我们再来仔细分析一下Synchronzied关键字,
Synchronzied关键字对线程来说就是这么一回事:
1) 线程进入synchronized代码块:尝试获得对象锁
2) 线程出了synchronized代码块:释放对象锁
说白了,就是谁有锁,谁就可以继续干活,没有就得等。
加锁就是限制同一时间有多个线程同时去访问公共的资源。

但是问题也就来了,synchronized可以限制对公共的资源访问,
但是无法决定线程访问公共资源的顺序,所以引入了wait(),
Notify(), notifyAll 等原语来控制线程访问的顺序。
注意这3个原语是当前对象的方法,不是当前线程的方法。

那么让我们来看看这三个原语有什么用:
1) wait(): 使当前线程阻塞,释放它所获得的对象的锁
2) notify(): 通知虚拟机当前线程准备要释放它所获得的对象的锁,
               当调用了wait()方法或者当这个线程出了synchronized
               代码块之后,这两个动作就是释放了当前线程对对象的锁的持有,
               那么其它的被阻塞的线程又可以执行了。
3) notify(): 跟notify()没有什么大区别,notify是通知1个被阻塞的线程做准备,
               notifyAll()是通知所有被阻塞的线程做准备,至于哪个线程可以获得
               这个锁,那就看JVM的啦!

所以对于上面的生产者与消费者的例子,
正确的流程是,
如果消费者有东西可以消费,那么我们就让他消费,
如果还需要生产,还可以生产,那么我们就让生产者生产,
只需要修改CustomerThread类ProductorThread类,
Food类 MainTest类。
那么我们的最终代码如下:
CustomerThread类:
Java代码 复制代码 收藏代码
  1. public class CustomerThread extends Customer implements Runnable {   
  2.   
  3.     private Food food = null;   
  4.   
  5.     public CustomerThread(Food food) {   
  6.         super("Customer");   
  7.         this.food = food;   
  8.     }   
  9.   
  10.     public void run() {   
  11.         this.consume();   
  12.     }   
  13.        
  14.     public void startConsume() {   
  15.         Thread thread = new Thread(this);   
  16.         thread.start();   
  17.     }   
  18.   
  19.     private void consume() {   
  20.         synchronized(food) {   
  21.             while(true) {   
  22.                 if(food.getFoodNum() <= 0) {   
  23.                     try {   
  24.                         food.wait();   
  25.                     } catch (InterruptedException e) {   
  26.                         // Do nothing   
  27.                     }   
  28.                 } else {   
  29.                     break;   
  30.                 }   
  31.             }   
  32.             int num = this.food.getFoodNum();   
  33.             num--;   
  34.             this.food.setFoodNum(num);   
  35.             System.out.println(this.getName() + " " + "consume food " + num);   
  36.             food.notify();   
  37.         }   
  38.     }   
  39. }  


ProductorThread类:
Java代码 复制代码 收藏代码
  1. public class ProductorThread extends Productor implements Runnable {   
  2.   
  3.     private Food food = null;   
  4.        
  5.     public ProductorThread(Food food) {   
  6.         super("Productor");   
  7.         this.food = food;   
  8.     }   
  9.   
  10.     public void run() {   
  11.         this.increase();   
  12.     }   
  13.        
  14.     public void startIncrease() {   
  15.         Thread thread = new Thread(this);   
  16.         thread.start();   
  17.     }   
  18.   
  19.     private void increase() {   
  20.         synchronized(food) {   
  21.             while(true) {   
  22.                 if(food.getFoodNum() == Food.MAX_NUM) {   
  23.                     try {   
  24.                         food.wait();   
  25.                     } catch (InterruptedException e) {   
  26.                         // Do nothing   
  27.                     }   
  28.                 } else {   
  29.                     break;   
  30.                 }   
  31.             }   
  32.             int num = this.food.getFoodNum();   
  33.             num++;   
  34.             this.food.setFoodNum(num);   
  35.             System.out.println(this.getName() + " " + "increase food " + num);   
  36.             food.notify();   
  37.         }   
  38.     }   
  39. }  


Food类:
Java代码 复制代码 收藏代码
  1. public class Food {   
  2.   
  3.     public static final int MAX_NUM = 10;   
  4.   
  5.     private int foodNum = 0;   
  6.   
  7.     public Food(int foodNum) {   
  8.         this.foodNum = foodNum;   
  9.     }   
  10.   
  11.     public void setFoodNum(int foodNum) {   
  12.         this.foodNum = foodNum;   
  13.     }   
  14.   
  15.     public int getFoodNum() {   
  16.         return this.foodNum;   
  17.     }   
  18. }  


MainTest类:
Java代码 复制代码 收藏代码
  1. public class MainTest {   
  2.     public static void main(String[] args) {   
  3.         Food food = new Food(0);   
  4.            
  5.         CustomerThread customer = new CustomerThread(food);   
  6.         customer.startConsume();   
  7.         CustomerThread customer1 = new CustomerThread(food);   
  8.         customer1.startConsume();   
  9.         CustomerThread customer2 = new CustomerThread(food);   
  10.         customer2.startConsume();   
  11.         CustomerThread customer3 = new CustomerThread(food);   
  12.         customer3.startConsume();   
  13.         CustomerThread customer4 = new CustomerThread(food);   
  14.         customer4.startConsume();   
  15.         CustomerThread customer5 = new CustomerThread(food);   
  16.         customer5.startConsume();   
  17.            
  18.         ProductorThread productor = new ProductorThread(food);   
  19.         productor.startIncrease();   
  20.         ProductorThread productor1 = new ProductorThread(food);   
  21.         productor1.startIncrease();   
  22.         ProductorThread productor2 = new ProductorThread(food);   
  23.         productor2.startIncrease();   
  24.         ProductorThread productor3 = new ProductorThread(food);   
  25.         productor3.startIncrease();   
  26.         ProductorThread productor4 = new ProductorThread(food);   
  27.         productor4.startIncrease();   
  28.         ProductorThread productor5 = new ProductorThread(food);   
  29.         productor5.startIncrease();   
  30.   
  31.   
  32.   
  33.     }   
  34. }  


终于写完了,累死我了~~~

 

1.1介绍线程和运行(Introducing Thread and Runnable)

线程类提供了线程结构,其中包含了潜在地去操作系统的接口。(这个操作通常是请求创建和管理线程。)一个单一的操作系统线程也连接着一个Thread对象。 Runnable接口提供通过线程执行的代码,它也连接...

Thread、Runnable、Callable三种创建线程的简单示例及区别简介

一、继承Thread类 1、编写线程类,继承Thread类 2、重写run()方法 把该线程需要完成的任务代码写在run()中,也称为线程体 3...

java 创建线程的三种方法Callable,Runnable,Thread比较及用法

编写多线程程序是为了实现多任务的并发执行,从而能够更好地与用户交互。一般有三种方法,Thread,Runnable,Callable. Runnable和Callable的区别是, (1)Call...

Java中继承Thread和实现Runnable这两种创建线程有何区别

原文地址:点击打开链接 创建线程的两种方式 Java中线程的创建有两种方式: 1. 通过继承Thread类,重写Thread的run()方法,将线程运行的逻辑放在其中 2. 通过实现R...

java再复习——多线程之初识线程,并从源码角度分析start与run方法,Thread类与Runnable接口

进程与线程的概念。 进程:是操作系统为一个程序分配内存空间的基本单位。 线程:存在于一个进程里,是程序执行的基本单元。线程才是负责是去执行程序的。 java创建线程的方式: 一:继承T...

Java创建线程(Runnable接口和Thread类)

Java创建线程(Runnable接口和Thread类) 大多数情况,通过实例化一个Thread对象来创建一个线程。Java定义了两种方式: 实现Runnable 接口; 可以继承Thread类。...
  • singit
  • singit
  • 2017年04月17日 21:21
  • 289

java线程系列---Runnable和Thread的区别

 在java中可有两种方式实现多线程,一种是继承Thread类,一种是实现Runnable接口;Thread类是在java.lang包中定义的。一个类只要继承了Thread类同时覆写了本类中的r...

java线程系列---Runnable和Thread的区别

http://blog.csdn.net/wwww1988600/article/details/7309070     在java中可有两种方式实现多线程,一种是继承Thread类,一种是实现Run...

JAVA手册——线程简介之Runnable与Thread

由于java是纯面向对象的语言,因此,java的线程模型也是面向对象的。 java通过Thread类将线程所必需的功能封装了起来。要想建立一个线程,必须要有一个线程执行函数,这个线程执行函数对应Th...

Java线程的使用方法——Mr.Thread和Ms.Runnable

package com.zq.pdsu.chapter_02_Thread; public class Actor extends Thread { @Override public void ...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:java线程的简单例子(Thread and runnable)
举报原因:
原因补充:

(最多只允许输入30个字)