Java中Thread的使用、死锁以及生产者消费者问题详解
来源:互联网 发布:富特文格勒 知乎 编辑:程序博客网 时间:2024/06/05 20:48
线程的创建主要有四种方式,一种是直接继承Thread实现,另一种是引用接口Runable。这两种创建的线程可以多次使用。也可以运用内部类实现接口的创建。但是用这种方法创建的线程只能用一次。以下就是线程的四种创建方式的相关代码:
1 package java819; 2 3 public class TestThread { 4 public static void main(String[] args) { 5 MyThread1 mt = new MyThread1(); 6 MyThread2 mt2 = new MyThread2(); 7 mt.start(); 8 new Thread(mt2).start(); 9 new Thread() {//内部类实现10 public void run() {11 for (int i = 0; i < 100; i++) {12 System.out.println("++++线程3++++++" + i);13 }14 }15 }.start();16 new Thread(new Runnable() {17 18 @Override19 public void run() {20 for (int i = 0; i < 100; i++) {21 System.out.println("******线程4****" + i);22 }23 }24 }).start();25 for (int i = 0; i < 100; i++) {26 System.out.println("******主线程****" + i);27 }28 }29 }30 /**31 * 32 * 四种方法实现线程的创建,两种运用的是内部类 一种是实现接口,一种是继承线程33 * 34 */35 class MyThread1 extends Thread {36 @Override37 public void run() {38 for (int i = 0; i < 100; i++) {39 System.out.println("++++线程一++++++" + i);40 }41 }42 }43 class MyThread2 implements Runnable {44 @Override45 public void run() {46 for (int i = 0; i < 100; i++) {47 System.out.println("-----线程二-------" + i);48 }49 }50 }
当想让线程暂时暂停,进入休眠状态,可以用Sleep实现,该方法是静态方法,可以直接被Thread引用。可以在方法中设置休眠的时间。下面通过一个例子来说明Sleep的用法
1 package java819; 2 import java.io.IOException; 3 import java.nio.CharBuffer; 4 public class TestSleep { 5 public static void main(String[] args) { 6 Runner r = new Runner(); 7 Thread t1 = new Thread(r); 8 Thread t2 = new Thread(r); 9 t1.start();10 t2.start();11 }12 }13 class Runner implements Runnable {14 @Override15 public void run() {16 for (int i = 0; i < 200; i++) {17 if (i % 10 == 0 && i != 0) {18 try {19 Thread.sleep(1000); //Sleep的用法20 } catch (InterruptedException e) {21 e.printStackTrace();22 }23 }24 System.out.println("——————————线程————————————" + i);25 }26 }27 }
当想让一个线程先执行完再去执行另一个线程时,可以用Join方法将当前线程先执行完。下面通过一个例子来说明Join的用法。
1 package cn.yj3g; 2 public class TestJoin { 3 public static void main(String[] args) { 4 MyThread2 t1 = new MyThread2("zhangcun"); 5 t1.start(); 6 try { 7 t1.join();//先执行调用join方法的线程对象的run方法,完成后才调用这条语句所在的线程 8 } catch (InterruptedException e) { 9 e.printStackTrace();10 }11 12 for (int i = 1; i <= 10; i++) {13 System.out.println("------i am main thread");14 }15 }16 }17 class MyThread2 extends Thread { 18 MyThread2(String s) {19 super(s);20 }21 public void run() {22 for (int i = 1; i <= 10; i++) {23 System.out.println("I am " + getName());24 try {25 sleep(1000);26 } catch (InterruptedException e) {27 System.out.println("又被打爆了!");28 return;29 }30 }31 }32 }
当需要一个线程让出当前执行状态即CPU,给其他线程执行的机会,就需要使用Yield方法,使当前线程暂时阻塞,让程序去执行其他的线程。还是通过一个例子来说明。
1 package java819; 2 public class TestYield { 3 public static void main(String[] args) { 4 MyYield my1 = new MyYield(); 5 MyYield2 my2 = new MyYield2(); 6 my1.start(); 7 my2.start(); 8 9 }10 }11 class MyYield extends Thread {12 @Override13 public void run() {14 for (int i = 0; i < 100; i++) {15 System.out.println("数字为:" + i);16 if (i % 10 == 0 && i != 0) {17 yield();18 }19 }20 }21 }22 class MyYield2 extends Thread {23 @Override24 public void run() {25 for (int i = 0; i < 100; i++) {26 System.out.println("线程二数字为:" + i);27 if (i % 10 == 0 && i != 0) {28 yield();29 }30 }31 }32 }
判断当前线程是否还在执行可以使用Thread.currentThread().isAlive()实现。
如果想让某一个线程的优先级优先,可以通过setPriority来设置线程的优先级。当然也会有一个getPriority来获取优先级MinPriority=1,MaxPriority=10,NomPriority=5。下面通过一个例子来说明setPriority的用法。
1 package java819; 2 public class TestPriority { 3 public static void main(String[] args) { 4 T1 t = new T1(); 5 T2 tt = new T2(); 6 tt.setPriority(Thread.NORM_PRIORITY + 4);//设置线程的优先级来改变线程的优先级 7 t.start(); 8 tt.start(); 9 }10 }11 class T1 extends Thread {12 13 @Override14 public void run() {15 for (int i = 0; i < 100; i++) {16 System.out.println("线程T1" + i);17 }18 }19 }20 class T2 extends Thread {21 22 @Override23 public void run() {24 for (int i = 0; i < 100; i++) {25 System.out.println("--------线程T2" + i);26 }27 }28 }
如果想实现当一个线程在占用一个资源时,不让别的线程来抢占资源,可以使用synchronized来修饰方法或者语句块,这样别的线程就不会进入synchronized修饰的方法或者方法块。
wait()和sleep()的区别:
<1>wait()时别的线程可以访问锁定对象。
<2>调用该方法时必须锁定该对象。
<3>sleep()时别的线程不可以访问锁定对象。
如果两个线程互相占用对方资源,那么线程将会进入死锁状态,在实现线程时,应该尽量避免死锁情况。下面就是一个典型的死锁例子,在编程时,我们应该要避免死锁的发生。
死锁例子:
1 package java819; 2 public class TestDeadLock implements Runnable { 3 public int flag = 1; 4 static Object o1 = new Object(), o2 = new Object(); 5 @Override 6 public void run() { 7 System.out.println("flag=" + flag); 8 if (flag == 1) { 9 synchronized (o1) {10 try {11 Thread.sleep(500);12 } catch (Exception e) {13 e.printStackTrace();14 }15 synchronized (o2) {16 System.out.println("1");17 }18 }19 }20 if (flag == 0) {21 synchronized (o2) {22 try {23 Thread.sleep(500);24 } catch (Exception e) {25 e.printStackTrace();26 }27 synchronized (o1) {28 System.out.println("0");29 }30 }31 }32 }33 public static void main(String[] args) {34 TestDeadLock td1 = new TestDeadLock();35 TestDeadLock td2 = new TestDeadLock();36 td1.flag = 1;37 td2.flag = 0;38 Thread t1 = new Thread(td1);39 Thread t2 = new Thread(td2);40 t1.start();41 t2.start();42 }43 }
通过以上所学的知识,我们就可以实现生活中常遇到的一个生产者消费者问题。下面我就通过一个实例来对这个问题进行下说明。
生产者消费者问题:
1 package cn.yj3g; 2 public class TestPC { 3 public static void main(String[] args) { 4 PizzaStack ps = new PizzaStack(); 5 6 Thread t1 = new Thread(new Cooker(ps)); 7 Thread t3 = new Thread(new Cooker(ps)); 8 Thread t5 = new Thread(new Cooker(ps)); 9 Thread t2 = new Thread(new Customer(ps)); 10 Thread t4 = new Thread(new Customer(ps)); 11 t1.start(); 12 t3.start(); 13 t2.start(); 14 t4.start(); 15 t5.start(); 16 } 17 } 18 /* 19 * 厨子 20 */ 21 class Cooker implements Runnable { 22 PizzaStack ps; 23 24 public Cooker(PizzaStack ps) { 25 this.ps = ps; 26 } 27 28 @Override 29 public void run() { 30 ps.push(); 31 } 32 } 33 /* 34 * 食客 35 */ 36 class Customer implements Runnable { 37 PizzaStack ps; 38 public Customer(PizzaStack ps) { 39 this.ps = ps; 40 } 41 @Override 42 public void run() { 43 ps.pop(); 44 } 45 } 46 /* 47 * pizza 48 */ 49 class Pizza { 50 int id; 51 public Pizza(int id) { 52 this.id = id; 53 } 54 public String toString() { 55 return "pizza "+id; 56 } 57 } 58 /* 59 * pizza筐 60 */ 61 class PizzaStack { //栈 62 private Pizza[] ps = new Pizza[10]; 63 int size; 64 public void push() { 65 while(size>=0 && size<ps.length) { 66 synchronized (this) {//此语句块锁住 67 this.notifyAll();//唤醒所有线程 68 Pizza p = new Pizza(size); 69 ps[size++] = p; 70 System.out.println("+++++++生产了"+p+" 剩下"+size+"个"); 71 } 72 try { 73 Thread.sleep((long)(Math.random()*1000)); 74 } catch (InterruptedException e) { 75 e.printStackTrace(); 76 } 77 } 78 try { 79 synchronized (this) { 80 wait(); 81 } 82 } catch (InterruptedException e) { 83 84 } 85 push(); 86 } 87 public void pop() { 88 while(size>0 && size<=ps.length) { 89 synchronized(this) { 90 this.notifyAll(); 91 Pizza p = ps[--size]; 92 System.out.println("------消费了"+p+" 剩下"+size+"个"); 93 } 94 try { 95 Thread.sleep((long)(Math.random()*1000)); 96 } catch (InterruptedException e) { 97 e.printStackTrace(); 98 } 99 } 100 try {101 synchronized (this) {102 wait();103 }104 } catch (InterruptedException e) {105 }106 pop();107 } 108 }
以上就是有关线程的全部内容,在以后的编程中我们会经常用到线程,所以这方面的知识要牢牢掌握。
- Java中Thread的使用、死锁以及生产者消费者问题详解
- Java中Thread的使用、死锁以及生产者消费者问题详解
- java多线程同步以及线程间通信详解&消费者生产者模式&死锁&Thread.join()(多线程编程之二)
- java多线程同步以及线程间通信详解&消费者生产者模式&死锁&Thread.join()(多线程编程之二)
- Java 多线程编程(生产者和消费者问题以及死锁)
- java--thread 生产者消费者问题
- java 生产者消费者问题以及线程池的使用
- 线程的相关知识、JAVA实现死锁、生产者消费者问题
- java 生产者消费者问题-多线程与死锁
- Java中,生产者和消费者的问题
- Java生产者消费者问题详解
- 生产者/消费者问题Java详解
- 多线程Thread生产者和消费者的问题
- 再谈java线程以及经典的生产者,消费者问题
- java中使用阻塞队列解决生产者消费者问题
- Java多线程编程中生产者-消费者模式的详解
- Java多线程编程中生产者-消费者模式的详解
- 2016-08-19-java-关于线程的死锁的案例分析:生产者消费者问题
- CentOS-6.6安装配置Nginx
- charisma-master中绘points图时遇到问题及解决方法
- findViewById()与Inflate()和setContentView()关系扯谈
- JAVA文件目录的遍历列表
- Attribute属性设置
- Java中Thread的使用、死锁以及生产者消费者问题详解
- CrossApp的环境配置教程Windows&mac
- GTK进阶学习:属性改变事件
- 应用程序无法启动,因为应用程序的并行配置不正确。
- Android NDK *** could not be resolved
- C#解决“Emgu.CV.CvInvoke”的类型初始值设定项引发异常 的其中一个办法
- iOS UIPickerView
- D3D绘制彩色立方体
- Android 更新模块