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. Public void run() {
  6. System.out.println(“Hello world”);
  7. }
  8. }
Pubilc class MyThread {
Pubilc MyThread() {
Super();
}
Public void run() {
System.out.println(“Hello world”);
}
}

当你要是用它的时候

Java代码  
  1. Publi class ThreadTest {
  2. Public static void main(String[] args)  {
  3. MyThread app = new MyThread();
  4. App.start();
  5. }
  6. }
Publi class ThreadTest {
Public static void main(String[] args)  {
MyThread app = new MyThread();
App.start();
}
}

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

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

那么看下面的例子:
食物类:

Java代码  
  1. public class Food {
  2. private int foodNum = 0;
  3. public Food(int foodNum) {
  4. this.foodNum = foodNum;
  5. }
  6. public void setFoodNum(int foodNum) {
  7. this.foodNum = foodNum;
  8. }
  9. public int getFoodNum() {
  10. return this.foodNum;
  11. }
  12. }
public class Food {
private int foodNum = 0;
public Food(int foodNum) {
this.foodNum = foodNum;
}
public void setFoodNum(int foodNum) {
this.foodNum = foodNum;
}
public int getFoodNum() {
return this.foodNum;
}
}

消费者类:

Java代码  
  1. public class Customer {
  2. private String name = "";
  3. public Customer(String name) {
  4. this.setName(name);
  5. }
  6. protected void setName(String name) {
  7. this.name = name;
  8. }
  9. protected String getName() {
  10. return this.name;
  11. }
  12. }
public class Customer {
private String name = "";
public Customer(String name) {
this.setName(name);
}
protected void setName(String name) {
this.name = name;
}
protected String getName() {
return this.name;
}
}

消费者线程类:

Java代码  
  1. public class CustomerThread extends Customer implements Runnable {
  2. private Food food = null;
  3. public CustomerThread(Food food) {
  4. super("Customer");
  5. this.food = food;
  6. }
  7. public void run() {
  8. this.consume();
  9. }
  10. public void startConsume() {
  11. Thread thread = new Thread(this);
  12. thread.start();
  13. }
  14. private void consume() {
  15. int num = this.food.getFoodNum();
  16. num++;
  17. this.food.setFoodNum(num);
  18. System.out.println(this.getName() + " " + "consume food");
  19. }
  20. }
public class CustomerThread extends Customer implements Runnable {
private Food food = null;
public CustomerThread(Food food) {
super("Customer");
this.food = food;
}
public void run() {
this.consume();
}
public void startConsume() {
Thread thread = new Thread(this);
thread.start();
}
private void consume() {
int num = this.food.getFoodNum();
num++;
this.food.setFoodNum(num);
System.out.println(this.getName() + " " + "consume food");
}
}

生产者类:

Java代码  
  1. public class Productor {
  2. private String name = "";
  3. public Productor(String name) {
  4. this.name = name;
  5. }
  6. protected void setName(String name) {
  7. this.name = name;
  8. }
  9. protected String getName() {
  10. return this.name;
  11. }
  12. }
public class Productor {
private String name = "";
public Productor(String name) {
this.name = name;
}
protected void setName(String name) {
this.name = name;
}
protected String getName() {
return this.name;
}
}

消费者类:

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

测试类:

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. }
public class MainTest {
public static void main(String[] args) {
Food food = new Food(0);
ProductorThread productor = new ProductorThread(food);
productor.startIncrease();
CustomerThread customer = new CustomerThread(food);
customer.startConsume();
}
}

上面代码主要模拟了生产者和消费者生产食物,消费食物的过程,
这里面先让生产者生产了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. }
 private synchronized void consume() {
int num = this.food.getFoodNum();
num++;
this.food.setFoodNum(num);
System.out.println(this.getName() + " " + "consume food");
}
private synchronized void increase() {
int num = this.food.getFoodNum();
num--;
this.food.setFoodNum(num);
System.out.println(this.getName() + " " + "increase food");
}

那么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. }
 private synchronized void consume() {
int num = this.food.getFoodNum();
num++;
this.food.setFoodNum(num);
System.out.println(this.getName() + " " + "consume food");
}

当线程进入到这个方法的时候,这个线程就会获得这个方法所在对象的锁,
那么其他的进程想要进入这个方法,首先尝试去获得这个方法所在对象的锁,
但是已经被前一个线程霸占了,所只能等待,当前一个线程把这段代码执行
完毕,那么后来的线程就可以获得这个对象锁了,当然它进去后又会把后面的
线程阻塞在外面等待。
这种方法等同于:

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. }
  private void consume() {
synchronized(this) {
int num = this.food.getFoodNum();
num++;
this.food.setFoodNum(num);
System.out.println(this.getName() + " " + "consume food");
}
}

但是这种方法我们把整个对象都锁住了,其他线程想要执行这个类中的其它用
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. }
  private void consume() {
Object lock = new Object();
synchronized(lock) {
int num = this.food.getFoodNum();
num++;
this.food.setFoodNum(num);
System.out.println(this.getName() + " " + "consume food");
}
}

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. private Food food = null;
  3. public CustomerThread(Food food) {
  4. super("Customer");
  5. this.food = food;
  6. }
  7. public void run() {
  8. this.consume();
  9. }
  10. public void startConsume() {
  11. Thread thread = new Thread(this);
  12. thread.start();
  13. }
  14. private void consume() {
  15. synchronized(food) {
  16. while(true) {
  17. if(food.getFoodNum() <= 0) {
  18. try {
  19. food.wait();
  20. } catch (InterruptedException e) {
  21. // Do nothing
  22. }
  23. } else {
  24. break;
  25. }
  26. }
  27. int num = this.food.getFoodNum();
  28. num--;
  29. this.food.setFoodNum(num);
  30. System.out.println(this.getName() + " " + "consume food " + num);
  31. food.notify();
  32. }
  33. }
  34. }
public class CustomerThread extends Customer implements Runnable {
private Food food = null;
public CustomerThread(Food food) {
super("Customer");
this.food = food;
}
public void run() {
this.consume();
}
public void startConsume() {
Thread thread = new Thread(this);
thread.start();
}
private void consume() {
synchronized(food) {
while(true) {
if(food.getFoodNum() <= 0) {
try {
food.wait();
} catch (InterruptedException e) {
// Do nothing
}
} else {
break;
}
}
int num = this.food.getFoodNum();
num--;
this.food.setFoodNum(num);
System.out.println(this.getName() + " " + "consume food " + num);
food.notify();
}
}
}

ProductorThread类:

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

Food类:

Java代码  
  1. public class Food {
  2. public static final int MAX_NUM = 10;
  3. private int foodNum = 0;
  4. public Food(int foodNum) {
  5. this.foodNum = foodNum;
  6. }
  7. public void setFoodNum(int foodNum) {
  8. this.foodNum = foodNum;
  9. }
  10. public int getFoodNum() {
  11. return this.foodNum;
  12. }
  13. }
public class Food {
public static final int MAX_NUM = 10;
private int foodNum = 0;
public Food(int foodNum) {
this.foodNum = foodNum;
}
public void setFoodNum(int foodNum) {
this.foodNum = foodNum;
}
public int getFoodNum() {
return this.foodNum;
}
}

MainTest类:

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

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

  • 多线程问题.rar (19.1 KB)
  • 描述: 这篇文档和对应的源代码
  • 下载次数: 35

java线程的简单例子(Thread and runnable)相关推荐

  1. java 线程死锁简单例子_java 多线程死锁详解及简单实例

    java 多线程死锁 相信有过多线程编程经验的朋友,都吃过死锁的苦.除非你不使用多线程,否则死锁的可能性会一直存在.为什么会出现死锁呢?我想原因主要有下面几个方面: (1)个人使用锁的经验差异 (2) ...

  2. java实现死锁简单例子,Java死锁的简单例子

    Java死锁的简单例子 两个线程互相占有对方需要的资源而不释放,便形成了死锁. 代码如下: Program.java /** * 程序类 * @author michael * */ public c ...

  3. java线程runnable_java基础----多线程之Runnable(一)

    java线程的创建有两种方式,这里我们通过简单的实例来学习一下.一切都明明白白,但我们仍匆匆错过,因为你相信命运,因为我怀疑生活. java中多线程的创建 一.通过继承Thread类来创建多线程 pu ...

  4. 【Boost】boost库中thread多线程详解6——线程组简单例子

    如果你需要创建几个线程,考虑使用一个线程组对象thread_group来组织它们.一个thread_group对象可以使用多种方法管理线程.首先,可以使用一个指向动态创建的线程对象的指针作为参数来调用 ...

  5. 【Java线程】简单实现带界面的一对一聊天

    实现原理: 1.构建好窗体,在窗体中创建好相应的布局和控件: 2.为相应的控件(按钮:监听.连接.发送)添加事件: 3.使用到两个线程: a.监听线程:获取服务器端输入的端口号,构建socket,监听 ...

  6. java 线程局部存储,转载boost::thread简要分析(3):线程局部存储及其它

    多线程编程中还有一个重要的概念:Thread Local Store(TLS,线程局部存储),在boost中,TLS也被称作TSS,Thread Specific Storage. boost::th ...

  7. java线程学习,GitHub - zksir/thread: Java多线程学习

    Java多线程学习 threadcoreknowledge包----线程核心知识基础 createthreads包 创建线程 1.实现多线程的方法是1种还是2种还是4种? Oracle官方:2种,一种 ...

  8. java 线程(多线程)thread,案例:汉字打字练习(AWT-EventQuecue,AWT-Windows)

    实验目的 当Java程序包含图形用户界面(GUI)时,Java虚拟机在运行应用程序时会自动启动更多的线程,其中有两个重要的线程:AWT-EventQuecue和 AWT-Windows. AWT-Ev ...

  9. go能否直接调用java_Go调用Java的一个简单例子

    由于Java世界里有非常丰富的开源应用模型和轮子,而这些正是Go世界里面最缺乏的东西,所以我首先考虑的就是如何在Go里面调用现有的Java代码.早上写了个简单的Go调用Java的例子,在winxp环境 ...

最新文章

  1. ADB 查看 crash log
  2. PyramidBox笔记
  3. Java杂记之JVM内存模型
  4. Kinect开发笔记之一Kinect详细介绍
  5. myeclipse 安装jad反编译插件
  6. C++局部重载new delete方法剖析
  7. oracle 10g在redhat4.6上的安装
  8. Boost Asio dispatch()与post()的区别
  9. 高中生物神经系统的组成,初中生物神经系统考题
  10. 计算机表格名次教程,Word表格怎么算名次
  11. 《富爸爸穷爸爸》--读书笔记(5)-2020
  12. C#开发之——MonthCalendar(12.18)
  13. LSD(线段检测测试文件)
  14. Unreal Engine 4 渲染目标(Render Target)教程 之 可交互的草地(上)
  15. IDEA import飘红,清除缓存重启也不行
  16. ESP Matter 环境搭建
  17. 匿名管道(Pipe)和命名管道(FIFO)
  18. vim自动格式化代码转载
  19. 产品需求文档(PRD)札记
  20. 《华为机试》刷题之HJ84 统计大写字母个数

热门文章

  1. iOS开发常用的资源和资料
  2. Git 仓库设置记住密码
  3. C / C++ 软件项目的目录结构
  4. Spreadsheet Tracking
  5. 【机器视觉】 dev_set_paint算子
  6. 【Tools】Tools博客汇总
  7. Android开发中的多线程编程技术
  8. opencv图像清晰度计算_Python中的十大图像处理工具
  9. Xp下的程序编译成linux,WinXP下打造自己的linux 0.11简易编译环境(原创)
  10. 专科 java转go 翱翔之路(四)协议通信 锁,互斥锁 读写锁 条件变量锁 连接mysql 查询