java编程笔记21 线程
1,两种方法来创建线程:
1)继承Thread类实现run方法:
public class Hello1 extends Thread { String name; public Hello1(String n) { name = n; } public void run() { for (int i=1; i<=10; i++) { System.out.println(name+" Hello "+i); } } }
2)实现Runnable接口,实现run方法:
public class Hello2 implements Runnable { String name; public Hello2(String n) { name = n; } public void run() { for (int i=1; i<=10; i++) System.out.println(name+" Hello "+i); } }
推荐第二种方法;
2,产生Thread对象和启动线程
public class ThreadsExample1 { public static void main(String argv[]) { Hello1 h1 = new Hello1("Thread1"); Hello2 h2 = new Hello2("Thread2"); Thread t1 = new Thread(h1); Thread t2 = new Thread(h2); t1.start(); t2.start(); } }
3,停止线程运行
下面的run方法可以让线程一直运行:
public class Hello3 implements Runnable { String name; public Hello3(String n) { name = n; } public void run() { int i=0; while(true)//这样来写run方法 { i++; System.out.println(name+" Hello "+i); } } }
加一个循环条件来达到停止现成的效果:
public class Hello4 implements Runnable { String name; Boolean isStop; public Hello4(String n) { name = n; isStop = false; } public void run() { int i=0; while(!isStop) { i++; System.out.println(name+" Hello "+i); } } public void stop()//控制条件 { isStop = true; } }
当一个线程对象进入死亡状态后,就没有任何方法可以回到其他状态。
4,暂停线程运行
sleep方法:
yield方法
join方法,
来看join的一个例子:
MotherThread:
package ch22; public class MotherThread implements Runnable { public void run() { System.out.println("妈妈准备煮饭"); System.out.println("妈妈发现米酒用完了"); System.out.println("妈妈叫儿子去买米酒"); Thread son = new Thread(new SonThread()); son.start(); System.out.println("妈妈等待儿子把米酒买回来"); try { son.join(); } catch (InterruptedException ie) { System.err.println("发生异常!"); System.err.println("妈妈中断煮饭"); System.exit(1); } System.out.println("妈妈开始煮饭"); System.out.println("妈妈煮好饭了"); } }
SonThread:
package ch22; public class SonThread implements Runnable { public void run() { System.out.println("儿子出门去买米酒"); System.out.println("儿子买东西来回需5分钟"); try { for (int i=1; i<=5; i++) { Thread.sleep(1000); System.out.print(i+"分钟 "); } } catch (InterruptedException ie) { System.err.println("儿子发生意外"); } System.out.println("\n儿子买米酒回来了"); } }
Cooking:
package ch22; public class Cooking { public static void main(String argv[]) { Thread mother = new Thread(new MotherThread()); mother.start(); } }
运行结果:
5,数据同步处理
现在我们有这样一个线程:
package ch22; public class ShareData implements Runnable { int i; public void run() { while (i<10) { i++; for(int j=0; j<10000000; j++); System.out.println(Thread.currentThread().getName()+":"+i); } } }
现在我们来产生两个ShareData对象,并给两个Thread运行:
package ch22; public class ThreadsExample2 { public static void main(String argv[]) { ShareData s1 = new ShareData(); ShareData s2 = new ShareData(); Thread t1 = new Thread(s1); Thread t2 = new Thread(s2); t1.start(); t2.start(); } }
其结果如图:
可以看到,两个Thread对象在交互运行,Thread 0和Thread 1分别从0按顺序到10.
这是因为两个Thread共用了程序代码但是没有共用数据,下面我们来看程序代码和数据都共用的效果:
package ch22; public class ThreadsExample3 { public static void main(String argv[]) { ShareData s = new ShareData(); Thread t1 = new Thread(s);//两个小成共用一个对象ShareData Thread t2 = new Thread(s); t1.start(); t2.start(); } }
结果并不是你所想象的从0到10,而是:
这是为什么呢????
这是因为线程被分割运行了,具体分析略。
6,synchronized实现线程同步
synchronized(要取得锁的对象)
{
要锁定的代码
}
package ch22; public class SyncShareData implements Runnable { int i; public void run() { while (i<10) { /*锁的对象是SyncShareData自己,也就是说这个对象对应的线程要进行同步机制*/ synchronized(this) { i++; for(int j=0; j<10000000; j++); System.out.println(Thread.currentThread().getName()+":"+i); } } } }
package ch22; public class ThreadsExample4 { public static void main(String argv[]) { SyncShareData s = new SyncShareData(); /*t1和t2都是操作同一个SyncShareData对象的线程, * 要进行同步机制,因为SyncShareData实现了锁机制*/ Thread t1 = new Thread(s); Thread t2 = new Thread(s); t1.start(); t2.start(); } }
实现了两个线程对同一个对象操作的同步
7,等待wait与通报notify
生产者和消费者的例子:
package ch22; public class Storage { private int count;//当前库存值 private int size;//最大库存量 public Storage(int s) { size = s; } //类里的方法实现了锁,则调用这个方法必须取得这个类的对象的锁 public synchronized void addData(String n) { while (count == size)//注意为什么要用while循环而不是if { try { this.wait();//进入等待状态 } catch (InterruptedException e) { } } this.notify();//通知消费者可以消费了 count++; System.out.println(n+" make data count: "+count); } public synchronized void delData(String n) { while (count == 0) { try { this.wait(); } catch (InterruptedException e) { } } this.notify(); System.out.println(n+" use data count: "+count); count--; } }
package ch22; public class Producer extends Thread { private String name; private Storage s; public Producer(String n, Storage s) { name = n; this.s = s; } public void run() { while (true) { s.addData(name); try { sleep((int)Math.random()*3000); } catch (InterruptedException e) { } } } }
package ch22; public class Consumer extends Thread { private String name; private Storage s; public Consumer(String n, Storage s) { name = n; this.s = s; } public void run() { while (true) { s.delData(name); try { sleep((int)Math.random()*3000); } catch (InterruptedException e) { } } } }
package ch22; public class ThreadsExample5 { public static void main(String argv[]) { Storage s = new Storage(3); Producer p1 = new Producer("Producer1", s); Producer p2 = new Producer("Producer2", s); Consumer c1 = new Consumer("Consumer1", s); p1.start(); p2.start(); c1.start(); } }
.........
Producer1 make data count: 3
Consumer1 use data count: 3
Consumer1 use data count: 2
Producer1 make data count: 2
Consumer1 use data count: 2
Producer1 make data count: 2
.........