Android 学习系列 - Java 多线程
16lz
2021-01-23
Java 多线程
Thread
sample
class MyThread extends Thread { private String name; public MyThread(String name) { this.name = name; } @Override public void run() { //..... } } class Main { public static void main(String[] args) { MyThread a = new MyThread('A'); MyThread b = new MyThread('B'); a.start(); b.start(); } }
start 方法不能重复调用, 重复调用会出现java.lang.IllegalThreadStateException异常
Runnable
sample
class MyRunnable extend Runnable{ public MyRunnable() { } @Override public void run() { } } class Main { public static void main(String[] args) { MyRunnable a = new MyRunnable('A'); MyRunnable b = new MyRunnable('B'); Thread demoa = new Thread(a); Thread demob = new Thread(b); demoa.start(); demob.start(); } }
关于选择继承Thread还是实现Runnable接口?
其实Thread也是实现Runnable接口的:
class Thread implements Runnable { //… public void run() { if (target != null) { target.run(); } } }
Thread中的run方法调用的是Runnable接口的run方法。Thread和Runnable都实现了run方法,这种操作模式其实就是代理模式。
Thread和Runnable的区别
如果一个类继承Thread,则不适合资源共享。但是如果实现了Runable接口的话,则很容易的实现资源共享。
class MyThread implements Runnable{ private int ticket = 5; //5张票 public void run() { for (int i=0; i<=20; i++) { if (this.ticket > 0) { System.out.println(Thread.currentThread().getName()+ "正在卖票"+this.ticket--); } } }}public class lzwCode { public static void main(String [] args) { MyThread my = new MyThread(); new Thread(my, "1号窗口").start(); new Thread(my, "2号窗口").start(); new Thread(my, "3号窗口").start(); }}
实现Runnable接口比继承Thread类所具有的优势:
1):适合多个相同的程序代码的线程去处理同一个资源
2):可以避免java中的单继承的限制
3):增加程序的健壮性,代码可以被多个线程共享,代码和数据独立。
主线程和子线程之间的关系
在java中,每次程序运行至少启动2个线程。一个是main线程,一个是垃圾收集线程。因为每当使用java命令执行一个类的时候,实际上都会启动一个JVM,每一个jVM就是在操作系统中启动了一个进程。
主线程也有可能在子线程结束之前结束。并且子线程不受影响,不会因为主线程的结束而结束。
// 休眠两秒 Thread.sleep(2000); // 强制加入 thread.join(); // 后台线程 thread.setDaemon(true); /** * @author Rollen-Holt 后台线程 * */ class hello implements Runnable { // 虽然有一个死循环,但是程序还是可以执行完的。因为在死循环中的线程操作已经设置为后台运行了。 public void run() { while (true) { System.out.println(Thread.currentThread().getName() + "在运行"); } } public static void main(String[] args) { hello he = new hello(); Thread demo = new Thread(he, "线程"); demo.setDaemon(true); demo.start(); } } // 优先级 // 不要误以为优先级越高就先执行。谁先执行还是取决于谁先去的CPU的资源。 thread.setPriority(8); // 礼让 // 在线程操作中,也可以使用yield()方法,将一个线程的操作暂时交给其他线程执行。 Thread.currentThread().yield();
同步和死锁
/** * @author Rollen-Holt * */class hello implements Runnable { public void run() { for(int i=0;i<10;++i){ if(count>0){ try{ Thread.sleep(1000); }catch(InterruptedException e){ e.printStackTrace(); } System.out.println(count--); } } } public static void main(String[] args) { hello he=new hello(); Thread h1=new Thread(he); Thread h2=new Thread(he); Thread h3=new Thread(he); h1.start(); h2.start(); h3.start(); } private int count=5;} //【运行结果】: // 5 // 4 // 3 // 2 // 1 // 0 // -1
这里出现了-1,显然这个是错的。应该票数不能为负值。
如果想解决这种问题,就需要使用同步。所谓同步就是在统一时间段中只有有一个线程运行,其他的线程必须等到这个线程结束之后才能继续执行。
使用线程同步解决问题
使用同步代码块
和同步方法
同步代码块
synchronized(同步对象){ //需要同步的代码 }
/** * @author Rollen-Holt * */class hello implements Runnable { public void run() { for(int i=0;i<10;++i){ synchronized (this) { if(count>0){ try{ Thread.sleep(1000); }catch(InterruptedException e){ e.printStackTrace(); } System.out.println(count--); } } } } public static void main(String[] args) { hello he=new hello(); Thread h1=new Thread(he); Thread h2=new Thread(he); Thread h3=new Thread(he); h1.start(); h2.start(); h3.start(); } private int count=5;}
同步方法
synchronized 方法返回类型方法名(参数列表){ // 其他代码 }
/** * @author Rollen-Holt * */class hello implements Runnable { public void run() { for (int i = 0; i < 10; ++i) { sale(); } } public synchronized void sale() { if (count > 0) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(count--); } } public static void main(String[] args) { hello he = new hello(); Thread h1 = new Thread(he); Thread h2 = new Thread(he); Thread h3 = new Thread(he); h1.start(); h2.start(); h3.start(); } private int count = 5;}
死锁
当多个线程共享一个资源的时候需要进行同步,但是过多的同步可能导致死锁。
生产者,消费者问题
/* *面包类,用于存放厨师生产的面包 */public class Bread { private String producer; public Bread(String producer) { super(); this.producer = producer; } @Override public String toString() { return producer; }} /* * 篮子类,用于存放面包 * 篮子假定最多放10个面包 */ public class Basket { private int index = 0; private Bread[] arrayBread = new Bread[10]; /* * 此方法用于往篮子里扔面包 每当厨师生成好一个面包就往篮子里边扔 由于当某一个厨师在往篮子扔面包的过程(还没扔完,但是面包已经在篮子里), * 又有一个厨师要往篮子里扔面包。 如果这是篮子里已经有9个面包的话,最后一个厨师就不能在扔了。 * 所以需要给这个方法加把锁,等一个厨师扔完后,另外一个厨师才能往篮子里扔。 */ public synchronized void push(int id, Bread bread) { System.out.println("生成前篮子里有面包:" + index + " 个"); // 当厨师发现篮子满了,就在那里不停的等着 while (index == arrayBread.length) { System.out.println("篮子满了,我开始等等。。。。。。"); try { // 厨师(一个生产线程)开始不停等待 // 他需要等待顾客(一个消费线程)把它叫醒 this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // 唤醒一个正在等待的线程,如果唤醒的线程为生产线程,则又会进入等待状态, // 如果为消费线程,则因生产线程生产了面包的缘故,消费线程可以进行消费 this.notify(); arrayBread[index] = bread; index++; System.out.println(bread); } /* * 此方法用于往篮子里拿面包 加锁原因和上边一样 */ public synchronized Bread pop(int id) { System.out.println("消费前篮子里有面包:" + index + " 个"); while (index == 0) { System.out.println("篮子空了,我开始等等。。。。。。"); try { // 顾客(一个消费线程)开始不停等待 // 他需要等待厨师(一个生产线程)把它叫醒 this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // 唤醒一个正在等待的线程,如果唤醒的线程为消费线程,则又会进入等待状态, // 如果为生产线程,则因生产线程消费了面包的缘故,生产线程可以进行生产 this.notify(); index--; System.out.println("第" + id + "个顾客消费了 -->" + arrayBread[index]); return arrayBread[index]; } }/* * 厨师类,用于生产面包 */ public class Kitchener implements Runnable { private Basket basket; private int id; public Kitchener(int id,Basket basket) { super(); this.id = id; this.basket = basket; } @Override public void run() { //让厨师生产10个面包 for (int i = 1; i <= 10; i++) { Bread bread = new Bread("第" + id + "个厨师生成的面包"); basket.push(id,bread); try { Thread.sleep(1); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } /* * 顾客类,用于消费面包 */ public class Customer implements Runnable { private Basket basket; private int id; public Customer(int id,Basket basket) { super(); this.id = id; this.basket = basket; } @Override public void run() { // 让顾客消费10个面包 for (int i = 1; i <= 10; i++) { basket.pop(id); try { Thread.sleep(2000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }public class Test { public static void main(String[] args) { Basket basket = new Basket(); // 两个厨师两个客户 Kitchener kitchener1 = new Kitchener(1,basket); Kitchener kitchener2 = new Kitchener(2,basket); Customer customer1 = new Customer(1,basket); Customer customer2 = new Customer(2,basket); new Thread(kitchener1).start(); new Thread(kitchener2).start(); new Thread(customer1).start(); new Thread(customer2).start(); } }
名字和年龄对应错误了,
http://www.cnblogs.com/rollenholt/archive/2011/08/28/2156357.html
更多相关文章
- Android 判断当前线程是否是UI主线程
- Android 线程
- Android AsyncTask异步线程
- Android 开发艺术探索读书笔记 11 -- Android 的线程和线程池
- Android线程模型
- android开发——通过子线程更新界面UI
- Android中AsyncTask(异步任务)和Handler(线程消息机制)的详解