黑马程序员_多线程

来源:互联网 发布:酒店经理上班时间 知乎 编辑:程序博客网 时间:2024/06/04 14:31
------- android培训、java培训、期待与您交流! ----------

1,对于多线程来说,首先要考虑的就是线程安全问题.

先来看一个卖票系统的例子,车站要卖100张票,有2个卖票窗口,

要解决线程安全问题就需要做到同步互斥.

把2个线程要访问的共享数据存放在一个类中,


注意:synchronized(x),锁的钥匙一定要用同一个,不然就是不同的锁,无法实现互斥的效果,

同一段代码中最好别出现2个锁,不然会造成死锁.

package cn.hmm.thread2;//卖票系统,每个线程卖一张public class ThreadSaletitck{        public static void main(String[] args){            res1 r = res1.get();            Thread d1 = new Thread(new sale1(r));            Thread d2 = new Thread(new sale2(r));            d1.start();            d2.start();    }}//设计一个单例,用饿汉式class res1{      public int num = 100;      public boolean flag = true;      private res1(){            }      static res1 Obj = null;      public static res1 get(){      if(Obj==null){      Obj = new res1();      }      return Obj;      }}//售票站1class sale1 implements Runnable{      private res1 r;      sale1(res1 r){              this.r = r;      }      public void run(){      while(true){      synchronized(r){      if(r.flag){      System.out.println("sale1 "+ r.num--);      r.flag = false;      if(r.num<=1)      return;      }      }      }      }}//售票站2class sale2 implements Runnable{    private res1 r;    sale2(res1 r){            this.r = r;    }    public void run(){    while(true){    synchronized(r){    if(!r.flag){    System.out.println("sale2 "+ r.num--);    r.flag = true;    if(r.num<=1)    return;    }    }    }    }}

2,再来看一个例子:主线程先循环100次,然后再子线程循环10次,再主线程循环100次,子线程循环10次.....一直这样循环50次.

要解决这个问题也要用到同步互斥,可以把主线程循环100次和子线程循环10次写到2个方法上门,然后再封装到一个类中.

再创建出一个对象,调用这个对象上的2个方法.在这个类中用一个共享的布尔型变量作为标记,实现等待唤醒操作,代码如下:

package cn.hmm.thread;public class TraditionalThreadCommunication {/** * 主线程先循环50次,然后再子线程循环10次,再主线程循环50次,子线程循环10次..... * 一直这样循环50次 *  */public static void main(String[] args) throws InterruptedException {// TODO 自动生成的方法存根]final Business business = new Business();new Thread(new Runnable(){public void run(){for(int i=1;i<=50;i++){try {business.sun(i);} catch (InterruptedException e) {// TODO 自动生成的 catch 块e.printStackTrace();}}}}).start();for(int i=1;i<=50;i++){business.main(i);}}}class Business{boolean bShouldSub = true;public synchronized void sun(int i) throws InterruptedException{while(bShouldSub){this.wait();}for(int j=1;j<=10;j++){System.out.println("sub thread:"+i+" loops:"+j);}bShouldSub = true;this.notify();}public synchronized void main(int i) throws InterruptedException{while(!bShouldSub){this.wait();}for(int j=1;j<=100;j++){System.out.println("main thread:"+i+" loops:"+j);}bShouldSub = false;this.notify();}}


3,创建线程的传统方法:

package cn.hmm.thread;public class TraditionalThread {/** * @param args */public static void main(String[] args) {createThread1();createThread2();createThread3();}//子类的run()方法覆盖了父类的run()方法private static void createThread3() {new Thread(new Runnable(){public void run(){for(int i=0;i<99;i++){try {Thread.sleep(500);} catch (InterruptedException e) {// TODO 自动生成的 catch 块e.printStackTrace();}System.out.println("Runnable:"+Thread.currentThread().getName());}}}){public void run(){for(int i=0;i<99;i++){try {Thread.sleep(500);} catch (InterruptedException e) {// TODO 自动生成的 catch 块e.printStackTrace();}System.out.println("Thread:"+Thread.currentThread().getName());}}}.start();}//方法二:常用的方法private static void createThread2() {Thread thread2 = new Thread(new Runnable(){public void run(){for(int i=0;i<99;i++){try {Thread.sleep(500);} catch (InterruptedException e) {// TODO 自动生成的 catch 块e.printStackTrace();}System.out.println(Thread.currentThread().getName());}}});thread2.start();}//方法一:不常用private static void createThread1() {Thread thread = new Thread(){public void run(){for(int i=0;i<99;i++){try {Thread.sleep(500);} catch (InterruptedException e) {// TODO 自动生成的 catch 块e.printStackTrace();}System.out.println(Thread.currentThread().getName());//System.out.println(this.getName());}}};thread.start();}}


4,定时器:

package cn.hmm.thread;import java.util.Date;import java.util.Timer;import java.util.TimerTask;//实现一次2秒一次4秒的交替,无限次的定时效果class MyTimetTask extends TimerTask{private static int count = 0;public void run(){count = (count+1)%2;System.out.println("bombing!");new Timer().schedule(new MyTimetTask(), 2000+2000*count);}}public class TraditionalTimerTest {public static void main(String[] args) {// TODO 自动生成的方法存根//creatTimer1();creatTimer2();}//实现一次2秒一次4秒的交替,无限次的定时效果private static void creatTimer2() {new Timer().schedule(new MyTimetTask(), 2*1000);while(true){System.out.println(new Date().getSeconds());try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO 自动生成的 catch 块e.printStackTrace();}}}@SuppressWarnings("deprecation")private static void creatTimer1() {new Timer().schedule(new TimerTask(){public void run(){System.out.println("bombing!");}}, 10*1000,3*1000);while(true){System.out.println(new Date().getSeconds());try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO 自动生成的 catch 块e.printStackTrace();}}}}


5,线程内数据共享,各线程数据不受到影响:

package cn.hmm.thread;import java.util.HashMap;import java.util.Map;import java.util.Random;public class ThreadScopeShareData {private static int data = 0;private static Map<Thread, Integer> threadData = new HashMap<Thread,Integer>();/** * @param args */public static void main(String[] args) {// TODO 自动生成的方法存根for(int i=0;i<2;i++){new Thread(new Runnable(){public void run(){data = new Random().nextInt(1000);System.out.println(Thread.currentThread().getName()+" data = "+data);threadData.put(Thread.currentThread(),data);new A().get();new B().get();}}).start();}/*new Thread(new Runnable(){public void run(){new A().get();new B().get();}}).start();*/}static class A{public void get(){int data = threadData.get(Thread.currentThread());System.out.println("A from "+Thread.currentThread().getName()+" get data:"+data);}}static class B{public void get(){int data = threadData.get(Thread.currentThread());System.out.println("B from "+Thread.currentThread().getName()+" get data:"+data);}}}


package cn.hmm.thread;import java.util.HashMap;import java.util.Map;import java.util.Random;public class ThreadScopeShareData2 {private static int data = 0;private static Map<Thread, Integer> threadData = new HashMap<Thread,Integer>();/** * @param args */private static ThreadLocal<Integer> x = new ThreadLocal<Integer>();public static void main(String[] args) {// TODO 自动生成的方法存根for(int i=0;i<2;i++){new Thread(new Runnable(){public void run(){data = new Random().nextInt(1000);x.set(data);System.out.println(Thread.currentThread().getName()+" data = "+data);//threadData.put(Thread.currentThread(),data);new A().get();new B().get();}}).start();}/*new Thread(new Runnable(){public void run(){new A().get();new B().get();}}).start();*/}static class A{public void get(){//int data = threadData.get(Thread.currentThread());int data = x.get();System.out.println("A from "+Thread.currentThread().getName()+" get data:"+data);}}static class B{public void get(){//int data = threadData.get(Thread.currentThread());int data = x.get();System.out.println("B from "+Thread.currentThread().getName()+" get data:"+data);}}}

6, JDK1.5的新特性 线程池:

package cn.hmm.thread2;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.ScheduledExecutorService;import java.util.concurrent.TimeUnit;public class ThreadPoolTest {/** * @param args */public static void main(String[] args) {// TODO 自动生成的方法存根//test1();test2();}private static void test2() {ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(3);threadPool.schedule(new Runnable(){public void run(){System.out.println("Bombing");}}, 10,TimeUnit.SECONDS);threadPool.shutdown();long start =System.currentTimeMillis();for(int i=0;i<20;i++){System.out.println(System.currentTimeMillis()-start);try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO 自动生成的 catch 块e.printStackTrace();}}}private static void test1() {//ExecutorService threadPool = Executors.newFixedThreadPool(3);//固定的线程池ExecutorService threadPool = Executors.newCachedThreadPool();//缓存的线程池for(int i=1;i<=10;i++){final int task =i;threadPool.execute(new Runnable(){public void run(){for(int j=1;j<=10;j++){try {Thread.sleep(20);} catch (InterruptedException e) {// TODO 自动生成的 catch 块e.printStackTrace();}System.out.println(Thread.currentThread().getName()+" is looping of "+j+" form task_"+task);}}});}System.out.println("all of 10 tasks have commotted!");threadPool.shutdown();}}


7,模拟处理16行日志,下面的代码产生了16个日志对象,当前代码需要运行16秒才能打印完这些日志。
修改程序代码,开四个线程让这16个对象在4秒钟打完。

package cn.hmm.thread2;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class Test {public static void main(String[] args){        System.out.println("begin:"+(System.currentTimeMillis()/1000));/*模拟处理16行日志,下面的代码产生了16个日志对象,当前代码需要运行16秒才能打印完这些日志。修改程序代码,开四个线程让这16个对象在4秒钟打完。*/ ExecutorService threadPool = Executors.newFixedThreadPool(4);for(int i=0;i<16;i++){  //这行代码不能改动final String log = ""+(i+1);//这行代码不能改动{ threadPool.execute(new Runnable(){ public void run(){ Test.parseLog(log); } });}}}//parseLog方法内部的代码不能改动public static void parseLog(String log){System.out.println(log+":"+(System.currentTimeMillis()/1000));try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}

总结:多线程并不能让程序运行的更快,但是多线程能让程序同时处理的事情变得更多,通过一些设计,可以让程序更快的完成任务.例如搜索用户磁盘中存在的文件.

------- Windows Phone 7手机开发、.Net培训、期待与您交流! -------

详细请查看:www.itheima.com

0 0