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异常
html
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接口的:java
class Thread implements Runnable { //… public void run() { if (target != null) { target.run(); } } }
Thread中的run方法调用的是Runnable接口的run方法。Thread和Runnable都实现了run方法,这种操做模式其实就是代理模式。多线程
若是一个类继承Thread,则不适合资源共享。可是若是实现了Runable接口的话,则很容易的实现资源共享。ide
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类所具备的优点:this
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,显然这个是错的。应该票数不能为负值。
若是想解决这种问题,就须要使用同步。所谓同步就是在统一时间段中只有有一个线程运行,其余的线程必须等到这个线程结束以后才能继续执行。code
使用同步代码块
和同步方法
htm
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