java多线程一 基本实现方法、消费者生产者队列、死锁
2018-01-10 17:30
836 查看
1.基本概念图
四个状态、start 代表被创建、run表示正在运行、阻塞(在干别的事情去了,可以把资源空出来给别人用)、死亡。
核心思想是提高cpu的使用率,你干别的事去了我来利用cpu啊,难点是同步,同时访问数据,一个厕所只有一个坑,俩个人一起上是不文明的。
参考:http://blog.csdn.net/zjwcdd/article/details/51517096
2.基本使用方法
俩种常用使用方法,一个是集成Thread类,一种是实现Runnable接口,因为java有单继承的限制,而接口Runnable可以重复实现多次,还可以利用线程池,推荐接口实现方法:1.继承方法
class JavaThread extends Thread{ private String name; public JavaThread(String name) { this.name=name; } public void run() { for (int i = 0; i < 5; i++) { System.out.println(name + "运行 : " + i); try { sleep((int) Math.random() * 10); } catch (InterruptedException e) { e.printStackTrace(); } } } } class Main { public static void main(String[] args) { JavaThread mTh1=new JavaThread("A"); JavaThread mTh2=new JavaThread("B"); mTh1.start(); mTh2.start(); } }
输出
B运行 : 0 A运行 : 0#可以发现A也可以抢cpu用 B运行 : 1 A运行 : 1 B运行 : 2 A运行 : 2 B运行 : 3 A运行 : 3 B运行 : 4 A运行 : 4
2.实现Runable接口
class JavaThread implements Runnable{ private String name; public JavaThread(String name) { this.name=name; } @Override//表示实现接口的时候重载了 public void run() { for (int i = 0; i < 5; i++) { System.out.println(name + "运行 : " + i); try { Thread.sleep((int) Math.random() * 10); } catch (InterruptedException e) { e.printStackTrace(); } } } } class Main { public static void main(String[] args) { new Thread(new JavaThread("C")).start(); new Thread(new JavaThread("D")).start(); } }
输出
C运行 : 0 D运行 : 0#可以发现D也在抢C的资源 C运行 : 1 D运行 : 1 C运行 : 2 D运行 : 2 C运行 : 3 D运行 : 3 C运行 : 4 D运行 : 4
另外提一点join,主进程做完了想关闭程序,你新建的子进程没干完事也也也也也也直接退出的话会出问题的,join是主进程等你一起退出,这个第一次用的时候坑了我好久。
参考:java多线程吐血整理http://blog.csdn.net/evankaka/article/details/44153709
3.生产者消费者模式
优点:利用很多个生产者(线程)去生产东西,利用很多个消费者(也是线程)去消费生产的东西,好处是利用多线程来处理,省时间。注意 生产者生产东西的总数有个限制,超过就暂时不生产,等消费者消费完,不然会通货膨胀。消费者有东西就消费,没东西就等待。难点:生产者和消费者之间的数据的同步的问题(一个文件只能同时让一个人在修改,一个厕所只能一个人同时在用)
模式图:
参考:https://www.cnblogs.com/chentingk/p/6497107.html
实现也有很多种方式:
可以参考这个:
生产者/消费者问题的多种Java实现方式http://blog.csdn.net/monkey_d_meng/article/details/6251879
这里举出另外一种:
import java.util.concurrent.BlockingQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; /** * 多线程模拟实现生产者/消费者模型 * * @author 林计钦 * @version 1.0 2013-7-25 下午05:23:11 */ public class ProducerConsumer { /** * * 定义装苹果的篮子 * */ public class Basket { // 篮子,能够容纳3个苹果 BlockingQueue<String> basket = new LinkedBlockingQueue<String>(3); // 生产苹果,放入篮子 public void produce() throws InterruptedException { // put方法放入一个苹果,若basket满了,等到basket有位置 basket.put("An apple"); } // 消费苹果,从篮子中取走 public String consume() throws InterruptedException { // take方法取出一个苹果,若basket为空,等到basket有苹果为止(获取并移除此队列的头部) return basket.take(); } } // 定义苹果生产者 class Producer implements Runnable { private String instance; private Basket basket; public Producer(String instance, Basket basket) { this.instance = instance; this.basket = basket; } public void run() { try { while (true) { // 生产苹果 System.out.println("生产者准备生产苹果:" + instance); basket.produce(); System.out.println("!生产者生产苹果完毕:" + instance); // 休眠300ms Thread.sleep(300); } } catch (InterruptedException ex) { System.out.println("Producer Interrupted"); } } } // 定义苹果消费者 class Consumer implements Runnable { private String instance; private Basket basket; public Consumer(String instance, Basket basket) { this.instance = instance; this.basket = basket; } public void run() { try { while (true) { // 消费苹果 System.out.println("消费者准备消费苹果:" + instance); System.out.println(basket.consume()); System.out.println("!消费者消费苹果完毕:" + instance); // 休眠1000ms Thread.sleep(1000); } } catch (InterruptedException ex) { System.out.println("Consumer Interrupted"); } } } public static void main(String[] args) { ProducerConsumer test = new ProducerConsumer(); // 建立一个装苹果的篮子 Basket basket = test.new Basket(); ExecutorService service = Executors.newCachedThreadPool(); Producer producer = test.new Producer("生产者001", basket); Producer producer2 = test.new Producer("生产者002", basket); Consumer consumer = test.new Consumer("消费者001", basket); service.submit(producer); service.submit(producer2); service.submit(consumer); // 程序运行5s后,所有任务停止 // try { // Thread.sleep(1000 * 5); // } catch (InterruptedException e) { // e.printStackTrace(); // } // service.shutdownNow(); } }
输出:
生产者准备生产苹果:生产者002 消费者准备消费苹果:消费者001 生产者准备生产苹果:生产者001 !生产者生产苹果完毕:生产者002 !生产者生产苹果完毕:生产者001 An apple !消费者消费苹果完毕:消费者001 生产者准备生产苹果:生产者001 !生产者生产苹果完毕:生产者001
参考:https://www.cnblogs.com/linjiqin/archive/2013/05/30/3108188.html
4.死锁
锁,同步是解决多线程下保证只有一个线程在处理这个文件的基本方式,我锁住了,别人就不能访问了,直到我不需要了,你才能访问它,上面中的线程安全的队列就是利用这个原理实现的,死锁就是A在等B某个访问结束,B也在等A某个访问结束,俩个都在等,一直等,这样就出现问题了。总感觉会出现这个问题是因为计算机太傻比了,访问的时候给文件加个锁,谁来我给谁,或者让它等不行吗?不可以吗?可能有另外的开销?为啥对线程上锁?是不是我理解错了。
上图中,就是俩个人都在等,都不服输,就会出现死锁,代码如下:
import java.util.Date; public class LockTest { public static String obj1 = "obj1"; public static String obj2 = "obj2"; public static void main(String[] args) { LockA la = new LockA(); new Thread(la).start(); LockB lb = new LockB(); new Thread(lb).start(); } } class LockA implements Runnable{ public void run() { try { System.out.println(new Date().toString() + " LockA 开始执行"); while(true){ synchronized (LockTest.obj1) { System.out.println(new Date().toString() + " LockA 锁住 obj1"); Thread.sleep(3000); // 此处等待是给B能锁住机会 synchronized (LockTest.obj2) { System.out.println(new Date().toString() + " LockA 锁住 obj2"); Thread.sleep(60 * 1000); // 为测试,占用了就不放 } } } } catch (Exception e) { e.printStackTrace(); } } } class LockB implements Runnable{ public void run() { try { System.out.println(new Date().toString() + " LockB 开始执行"); while(true){ synchronized (LockTest.obj2) { System.out.println(new Date().toString() + " LockB 锁住 obj2"); Thread.sleep(3000); // 此处等待是给A能锁住机会 synchronized (LockTest.obj1) { System.out.println(new Date().toString() + " LockB 锁住 obj1"); Thread.sleep(60 * 1000); // 为测试,占用了就不放 } } } } catch (Exception e) { e.printStackTrace(); } } }
输出就是A锁住了,B锁住了,然后就不动了:
Wed Jan 10 19:36:44 GMT+08:00 2018 LockA 开始执行 Wed Jan 10 19:36:44 GMT+08:00 2018 LockA 锁住 obj1 Wed Jan 10 19:36:44 GMT+08:00 2018 LockB 开始执行 Wed Jan 10 19:36:44 GMT+08:00 2018 LockB 锁住 obj2 后面就没有了
如何避免死锁呢,别一个锁着又去锁另外一个
import java.util.Date; public class UnLock { public static String obj1 = "obj1"; public static String obj2 = "obj2"; public static void main(String[] args) { LockA la = new LockA(obj1,obj2); new Thread(la).start(); LockB lb = new LockB(obj1,obj2); new Thread(lb).start(); } } class LockA implements Runnable{ private Object obj1; private Object obj2; public LockA(Object o1,Object o2){ this.obj1 = o1; this.obj2 = o2; } public void run() { String name = Thread.currentThread().getName(); System.out.println(name + " acquiring lock on " + obj1); synchronized (obj1) { System.out.println(name + " acquired lock on " + obj1); // work(); } System.out.println(name + " released lock on " + obj1); System.out.println(name + " acquiring lock on " + obj2); synchronized (obj2) { System.out.println(name + " acquired lock on " + obj2); // work(); } System.out.println(name + " released lock on " + obj2); System.out.println(name + " finished execution."); } } class LockB implements Runnable{ private Object obj1; private Object obj2; public LockB(Object o1,Object o2){ this.obj1 = o1; this.obj2 = o2; } public void run() { String name = Thread.currentThread().getName(); System.out.println(name + " acquiring lock on " + obj2); synchronized (obj2) { System.out.println(name + " acquired lock on " + obj2); // work(); } System.out.println(name + " released lock on " + obj2); System.out.println(name + " acquiring lock on " + obj1); synchronized (obj1) { System.out.println(name + " acquired lock on " + obj1); } System.out.println(name + " released lock on " + obj1); System.out.println(name + " finished execution."); } }
Thread-0 acquiring lock on obj1 Thread-1 acquiring lock on obj2 Thread-0 acquired lock on obj1 Thread-1 acquired lock on obj2 Thread-0 released lock on obj1 Thread-1 released lock on obj2 Thread-0 acquiring lock on obj2 Thread-1 acquiring lock on obj1 Thread-0 acquired lock on obj2 Thread-1 acquired lock on obj1 Thread-0 released lock on obj2 Thread-1 released lock on obj1 Thread-1 finished execution. Thread-0 finished execution.
相关文章推荐
- Java Note: 多线程的同步(互斥锁)的方法对比,信号量锁,读写锁的实现,生产者-消费者模式的实现
- Java Note: 多线程的同步(互斥锁)的方法对比,信号量锁,读写锁的实现,生产者-消费者模式的实现
- Java Note: 多线程的同步(互斥锁)的方法对比,信号量锁,读写锁的实现,生产者-消费者模式的实现
- Java Note: 多线程的同步(互斥锁)的方法对比,信号量锁,读写锁的实现,生产者-消费者模式的实现
- JAVA多线程-生产者与消费者当线程多时发生死锁的解决方法
- Java Note: 多线程的同步(互斥锁)的方法对比,信号量锁,读写锁的实现,生产者-消费者模式的实现
- Java Note: 多线程的同步(互斥锁)的方法对比,信号量锁,读写锁的实现,生产者-消费者模式的实现
- Java Note: 多线程的同步(互斥锁)的方法对比,信号量锁,读写锁的实现,生产者-消费者模式的实现
- 多线程编程之生产者消费者(java实现)
- Java多线程实现消费者/生产者模式
- 基于java多线程来实现生产者和消费者的实例
- java 用多线程实现多生产者和多消费者模式
- Java阻塞队列BlockingQueue实现生产者消费者-只有代码-不讲原理
- Java实现 简单的多线程“生产者-消费者”问题
- Java阻塞队列(BlockingQueue)实现 生产者/消费者 示例
- java利用lock和unlock实现消费者与生产者问题(多线程)
- 关于网宿厦门研发中心笔试的一道PV操作题:利用java中的多线程实现生产者与消费者的同步问题
- Java 多线程学习之生产者消费者模型:一个较完善的实现
- Java多线程生产者消费者调度实现
- Java 技术: 使您轻松地进行多线程应用程序编程——Consumer 类可以简化生产者-消费者行为的实现