Java 多线程

来源:互联网 发布:医疗服务行业数据 编辑:程序博客网 时间:2024/05/17 06:29

1.java多线程的两种形式

1.1Thread子类形式

public class MyThread extends Thread{    @Override    public void run() {        for (int i=0;i<500;i++){            System.out.println( getName()+":"+i);        }    }}public class ThreadDemo {    public static void main(String[] args) throws InterruptedException {        MyThread myThread1=new MyThread();        MyThread myThread2=new MyThread();        myThread1.start();        myThread2.start();        System.out.println("over...");    }}

1.2 Runable形式

class MyRunable implements Runnable{    @Override    public void run() {        for (int i=0;i<200;i++){            //注意这里调用线程名称的方式            System.out.println(Thread.currentThread().getName() + ":" + i);        }    }}public class ThreadRunableDemo {    public static void main(String[] args) {        Runnable r1= new MyRunable();        new Thread(r1,"clow").start();        new Thread(r1,"jop").start();        //当然也可以使用内部类        Runnable r2=new MyRunable(){            @Override            public void run() {                for (int i=10;i<120;i++){                    //注意这里调用线程名称的方式                    System.out.println(Thread.currentThread().getName() + ":" + (char)i);                }            }        };        new Thread(r2,"alex").start();    }}


1.3 内部类线程

内部类可以类比于C#的委托-拉姆达表达式,同层次的变量在run方法是可以直接使用的,这和拉姆达表达式一样
public class InnerThreadDemo {    public static void main(String[] args) {        //继承Thread类实现多线程        new Thread(){            @Override            public void run() {                for (int i=0;i<1000;i++){                    System.out.println(Thread.currentThread().getName()+": "+i);                }            }        }.start();        //使用Runnable实现        new Thread(new Runnable() {            @Override            public void run() {                for (int i=0;i<1000;i++){                    System.out.println(Thread.currentThread().getName()+": "+i);                }            }        }).start();    }}


1.4二者的比较

Runable解决了java单继承类的局限问题,而且它减少了代码的耦合性,所有推荐使用第二种方法!


2.电影票问题

假设一家电影院有3个电影售票窗口,同时出售《复仇者联盟4》的电影票共100张,如何模拟?

2.1Thread子类实现形式

class TicketTread extends Thread {    private static int ticketnum = 100;    @Override    public void run() {        while(ticketnum>0){            System.out.println("windows_"+ getName()+":The current ticket number is "+ticketnum--);        }    }}class TicketTreadDemo {    public static void main(String[] args) {        TicketTread t1=new TicketTread();        TicketTread t2=new TicketTread();        TicketTread t3=new TicketTread();        t1.start();        t2.start();        t3.start();    }}


2.2Runable 实现形式

class Ticket implements Runnable {    private int ticketnum = 100;    @Override    public void run() {        while(ticketnum>0){            System.out.println("windows_"+Thread.currentThread().getName()+":The current ticket number is "+ticketnum--);        }    }}class TicketRunableDemo {    public static void main(String[] args) {        Ticket t =new Ticket();        new Thread(t,"1").start();        new Thread(t,"2").start();        new Thread(t,"3").start();    }}

从上面的2例子可以看出对于相同的代码,使用runable的方法更灵活方便,但是他们都还存在一个问题,比如某一张票会被卖了2次,这就是所谓的临界区问题了。

2.3Runable 最终实现形式

如上的售票必须使用同步才行,java的synchronized方法和C#的lock方法类似。

class Ticket implements Runnable {    private int ticketnum = 100;    private Object obj = new Object();    @Override    public void run() {        synchronized (obj) {            while (ticketnum > 0) {                System.out.println("windows_" + Thread.currentThread().getName() + ":The current ticket number is " + ticketnum--);            }        }    }}

当然也可以使用同步方法放在run里面,但类是实例类的时候,它锁的对象的this; 当方法是静态的时候,它锁的是类的Xxx.class的字节码对象
 public synchronized void sellTicket(){        while (ticketnum > 0) {                System.out.println("windows_" + Thread.currentThread().getName() + ":The current ticket number is " + ticketnum--);            }    }


继jdk5推出了类似PV操作的上锁和解锁操作
class Ticket implements Runnable {    private int ticketnum = 100;    Lock lock=new ReentrantLock(); //实例化一个锁    @Override    public void run() {        try {            lock.lock(); //上锁            while (ticketnum > 0) {                System.out.println("windows_" + Thread.currentThread().getName() + ":The current ticket number is " + ticketnum--);            }        }finally {            lock.unlock(); //解锁        }    }}

2.线程池

1.Runable类型
lass ThreadPool implements Runnable {    @Override    public void run() {        for (int i=0;i<200;i++){            System.out.println(Thread.currentThread().getName()+" "+i);        }    }} class ThreadPoolDemo{     public static void main(String[] args) {         ExecutorService pool= Executors.newFixedThreadPool(2);//创建包含2个线程的线程池         pool.submit(new ThreadPool());         pool.submit(new ThreadPool());         //此时线程执行完会被回收,使用下面方法结束线程池         pool.shutdown();     } }

2.Callable类型
其和C#中的BackgroundWork类似,都是执行一段代码并返回结果。而在java中其自动阻塞主线程效果
class MyCallable implements Callable<Integer> {    private int number;    public MyCallable(int number){        this.number=number;    }    @Override    public Integer call() throws Exception {        int sum=0;        for (int i=1;i<=number;i++){            sum+=i;        }        Thread.sleep(7000);        return sum;    }}class MyCallableDemo{    public static void main(String[] args) throws Exception {        ExecutorService pool= Executors.newFixedThreadPool(2);        Future<Integer> f1=pool.submit(new MyCallable(100));        Future<Integer> f2=pool.submit(new MyCallable(200));        int i1=f1.get();//get会阻塞主线程直到拿到结果        int i2=f2.get();        System.out.println("打印输出");        System.out.println(i1);//5050        System.out.println(i2);//20100    }}

3.定时器

如下代码为当前显示时间
//schedule(TimerTask task, long delay, long period)//period为时间间隔class MyTask extends TimerTask{    @Override    public void run() {        System.out.println(new Date().toString());    }}class TimerDemo {    public static void main(String[] args) {        Timer t=new Timer();        TimerTask task=new MyTask();        t.schedule(task, 0, 1000); //第一次无延迟,每秒执行一次        //t.cancel(); //干掉时间任务的子线程,才能推出主线程        System.out.println("over..");    }}




0 0
原创粉丝点击