java:多线程(代理模式,Thread中的方法,Timer,生产者和消费者)

*进程:一个正在运行的程序,进程是操作系统分配资源的基本单位,每个进行有独立的内存空间,进程之间切换开销较大。
*线程:一个轻量级的进程,线程是任务调度的基本单位,一个进程可以有多个线程,
* 系统没有为线程分配额外的内存空间,一个进程中的多个线程共享内存空间,线程之间切换开销较小。
*创建线程的方式:
* 1.继承java.lang.Thread类,并重写run方法。
* 2.实现java.lang.Runnable接口,并重写run方法
*线程的启动:调用start()方法进行启动线程,而非调用run方法。

public class MyThread  extends Thread{
    public MyThread(String name){
        super(name);//调用Thread的构造方法,分配新的 Thread 对象
    }
    
    @Override
    public void run() {
        String name = getName();//获取线程的名称
        for (int i = 0; i < 10; i++) {
            System.out.println(name+"---->"+i);
        }
    }
}
public class MyThread2 implements Runnable{
    private String name;
    
    public MyThread2(String name){
        this.name=name;
    }
    
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(name+"======>"+i);
        }
    }

}
public class Test {
    public static void main(String[] args) {
        MyThread thread1 = new MyThread("A");
        MyThread2 thread2 = new MyThread2("B");
        thread1.start();//启动线程A
//        thread1.run(); //方法调用
        Thread t = new Thread(thread2);//创建代理
        t.start();//启动线程B
//        t.run(); //方法调用
    }
}

  代理模式:

public interface KindWoman {
    public void makeEyes();
}
public class PanJinLian implements KindWoman{
    public void makeEyes(){
        System.out.println("西门大官人,大郎出去卖了炊饼,今晚约吗?");
    }
}
public class YanPoXi implements KindWoman{
    public void makeEyes(){
        System.out.println("西门大官人,宋押司会见梁山好汉了,今晚约吗?");
    }
}
/**
 * 代理
 */
public class WangPo {
//    PanJinLian panJinLian;
    KindWoman woman;//被代理者
    public WangPo(KindWoman woman){
        this.woman=woman;
    }
    
    public void makeEyes(){
        System.out.println("西门大官人,我是王妈妈");
        woman.makeEyes();
    }
    
    public static void main(String[] args) {
        PanJinLian panJinLian = new PanJinLian();
        WangPo wangPo = new WangPo(panJinLian); 
        wangPo.makeEyes();
        System.out.println("--------------------");
        YanPoXi yanPoXi = new YanPoXi();
        WangPo  wangPo2 = new WangPo(yanPoXi);
        wangPo2.makeEyes();
    }
}

 Thread种的方法:

*java.lang.Thread类
*常用构造方法:
* Thread()
* Thread(String name)
* Thread(Runnable target)
*常用的方法:
* getName():获取线程的名称
* getId():获取线程的标识符Id
* getState()返回该线程的状态。
* getPriority() 返回线程的优先级。
* void setPriority(int newPriority):更改线程的优先级
* NORM_PRIORITY:默认优先级,值为5
* MAX_PRIORITY:最高优先级,值为10
* MIN_PRIORITY:最低优先级,值为1
* setName(String name)改变线程名称,使之与参数 name 相同。
* sleep(long millis) 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。
* start():启动线程***
* run():存放线程体中代码,不能显示调用。
* isAlive():判断线程是否还“活”着,即线程是未终止

public class MyThread2 extends Thread{
    private String name;//线程名称
    public MyThread2(String name){
        this.name=name;
    }
    
    @Override
    public void run() {
        System.out.println("线程"+name+"开始执行....");
        for (int i = 0; i < 10; i++) {
//            try {
//                Thread.sleep(1);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }

            System.out.println(name+"----->"+i);
        }
        System.out.println("线程"+name+"执行结束....");
    }
    
}
public class MyThread extends Thread{
    private String name;//线程名称
    public MyThread(String name){
        this.name=name;
    }
    
    @Override
    public void run() {
        System.out.println("线程"+name+"开始执行....");
        
        for (int i = 0; i < 10; i++) {
//            try {
//                Thread.sleep(1);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
            System.out.println(name+"----->"+i);
            try {
                join(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("线程"+name+"执行结束....");
    }
    
}
public class TestThread {
    public static void main(String[] args) {
        Thread t = Thread.currentThread();//获取当前线程
        t.setPriority(Thread.MAX_PRIORITY);//设置优先级
        t.setName("主线程");
        System.out.println("线程名称:"+t.getName());
        System.out.println("线程Id:"+t.getId());
        System.out.println("线程的优先级:"+t.getPriority());
        System.out.println("程序即将休眠1秒:");
        try {
            t.sleep(1000);//单位是毫秒.
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("当前线程是否活着:"+t.isAlive());
        System.out.println("休眠完毕!");
        
    }
}
public class TestMyThread {
/*
Join () 阻塞指定线程等到另一个线程完成以后再继续执行 
  Sleep () 使线程停止运行一段时间,将处于阻塞状态
  如果调用了sleep方法之后,没有其他等待执行的线程,这个时候当前线程不会马上恢复执行!
  yield () 让当前正在执行线程暂停,不是阻塞线程,而是将线程转入就绪状态
  如果调用了yield方法之后,没有其他等待执行的线程,这个时候当前线程就会马上恢复执行!
*/
public static void main(String[] args) { MyThread t1 = new MyThread("线程A"); MyThread2 t2 = new MyThread2("线程B"); // t1.setPriority(1); t1.start(); // t2.setPriority(10); t2.start(); } }

 

通过继承Thread类是不能用一个实例建立多个线程,故而实现Runnable接口适合于资源共享;

当然,继承Thread类也能够共享变量,能共享Thread类的static变量;

*模拟实现火车站售票窗口同时售票
* 50张车票,1000人在抢票
*Thread(Runnable target, String name) 分配新的 Thread 对象。

public class TicketSell implements Runnable{
    private int ticket=100;//50张火车票
    
    @Override
    public void run() {
        for(int i=1;i<=1000;i++){
            Thread t = Thread.currentThread();
            String name = t.getName();
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if(ticket>0){
                System.out.println(name+"卖出了"+(ticket--)+"号票");
            }
        }
    }
    
    public static void main(String[] args) {
        TicketSell ticketSell = new TicketSell();
        Thread t1 = new Thread(ticketSell,"A窗口");
        Thread t2 = new Thread(ticketSell,"B窗口");
        Thread t3 = new Thread(ticketSell,"C窗口");
        Thread t4 = new Thread(ticketSell,"D窗口");
        Thread t5 = new Thread(ticketSell,"E窗口");
        t1.start();
        t2.start();
        t3.start();
        t4.start();
        t5.start();
    }
    
}

* 模拟实现火车站售票窗口同时售票 50张车票,1000人在抢票
* Thread(Runnable target, String name) 分配新的Thread 对象。
* 问题:多个窗口同时售票的过程中有可能出现同一张票出售给不同人。 解决方案:利用线程同步进行解决
* 同步:类似生活中排队,同一时刻只能有一个线程操作资源,在程序中可以通过加锁完成线程同步。
* 同步的优点:保证数据的有效性 同步的缺点:效率较低。
* 利用以下两种方式实现同步
* 1.在java中可以通过synchronized关键字(同步监视器)来实现同步. 同步监视器:synchronized(obj){ obj:同步监视器
* //代码; }
* 2.使用同步方法(使用synchronized关键字修饰的方法)进行加锁

public class TicketSell3 implements Runnable {
    private Integer ticket = new Integer(100);// 50张火车票

    @Override
    public void run() {
        for (int i = 1; i <= 1000; i++) {
            Thread t = Thread.currentThread();
            String name = t.getName();
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            sale(name);
        }
    }
    /**
     * 同步的方法:
     * @param name
     */
    public synchronized void sale(String name) {
        if (ticket > 0) {
            System.out.println(name + "卖出了" + (ticket--) + "号票");
        }
    }

    public static void main(String[] args) {
        TicketSell3 ticketSell = new TicketSell3();
        Thread t1 = new Thread(ticketSell, "A窗口");
        Thread t2 = new Thread(ticketSell, "B窗口");
        Thread t3 = new Thread(ticketSell, "C窗口");
        Thread t4 = new Thread(ticketSell, "D窗口");
        Thread t5 = new Thread(ticketSell, "E窗口");
        t1.start();
        t2.start();
        t3.start();
        t4.start();
        t5.start();
    }

}

 eg2:

public class BankAccount implements Runnable{
    int blance=1000;
    @Override
    public void run() {
            String name = Thread.currentThread().getName();
            System.out.println(name+"开始取款....."+blance);
            for(int i=1;i<10;i++){
                try {
                    Thread.sleep(2);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
//                synchronized (this) {  //利用同步监视器实现线程同步
//                    if(blance>100){
//                        blance=blance-100;
//                        System.out.println(name+"取款100,余额为:"+blance);
//                    }
//                }
                draw();
            }
    }
    /**
     * 利用同步方法实现线程同步
     */
    public synchronized void  draw(){
        String name = Thread.currentThread().getName();
        if(blance>100){
            blance=blance-100;
            System.out.println(name+"取款100,余额为:"+blance);
        }
    }
    
    public static void main(String[] args) {
        BankAccount  bc = new BankAccount();
        Thread t1 = new Thread(bc, "张三");
        t1.start();
        Thread t2 = new Thread(bc,"张三老婆");
        t2.start();
    }
    
}

 

*死锁:当两个线程相互等待对方释放“锁”时就会发生死锁
*出现死锁后,不会出现异常,不会出现提示,只是所有的线程都处于阻塞状态,无法继续
*线程同步的优点:保证线程安全(数据安全有效)
*线程同步的缺点:效率低,有可能造成死锁问题。

public class TestDeadLock {
    public static void main(String[] args) {
        final DeadLock d1 = new DeadLock();
        final DeadLock d2 = new DeadLock();
        //使用匿名类创建线程
        new Thread("线程A"){
            public void run() {
                //调用d1的m1方法是需要对d2对象进行加锁
                d1.m1(d2);//匿名类访问外部的成员变量时,该成员必须使用final修饰
            };
        }.start();
        //使用匿名类创建线程
        new Thread("线程B"){
            public void run() {
                //调用d2的m1方法是需要对d1对象进行加锁
                d2.m1(d1);//匿名类访问外部的成员变量时,该成员必须使用final修饰
            };
        }.start();
    }
}
public class DeadLock {
    public synchronized void m1(DeadLock deadLock){
        String name = Thread.currentThread().getName();
        System.out.println(name+"进入m1方法....");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(name+"即将调用m2方法....");
        deadLock.m2();
    }
    
    public synchronized void m2(){
        String name = Thread.currentThread().getName();
        System.out.println(name+"进入m2方法....");
    }
}

*java.util.Timer类:定时器,一种工具,线程用其安排以后在后台线程中执行的任务
*java.util.TimerTask类实现Runnable接口,由 Timer 安排为一次执行或重复执行的任务。
*常用的构造方法:
* Timer()创建一个新计时器。
*常用的方法:
* schedule(TimerTask task, Date time)安排在指定的时间执行指定的任务。
* schedule(TimerTask task, long delay)安排在指定延迟后执行指定的任务。
* schedule(TimerTask task, Date firstTime, long period)
* 安排指定的任务在指定的时间开始进行重复的固定延迟执行。
* schedule(TimerTask task, long delay, long period)安排指定的任务从指定的延迟后开始进行重复的固定延迟执行。

public class MyTimerTask extends TimerTask{
    
    @Override
    public void run() {
        System.out.println("执行了MyTimerTask中的run方法。");
    }
    
    public static void main(String[] args) {
        Timer timer = new Timer();
//        timer.schedule(new MyTimerTask(), new Date());//在当前时间执行MyTimerTask中的任务(调用其中run方法)
//        timer.schedule(new MyTimerTask(), 5000);//延迟5000毫秒执行任务调度(调用MyTimerTask中run方法)
//        timer.schedule(new MyTimerTask(),new Date(),2000);//从当前时间开始,每个2000毫秒做一次任务调度
        timer.scheduleAtFixedRate(new MyTimerTask(), 5000, 2000);//延迟5000毫秒,每个2000毫秒执行一次任务调度
    }

}

 生产者和消费者:

/**
 * 馒头类
 * @author Administrator
 *
 */
public class SteamBread {
    private int id;//馒头的编号
    
    public SteamBread(int id){
        this.id=id;
    }
    
    @Override
    public String toString() {
        return "SteamBread [id=" + id + "]";
    }
    
}
/**
 * 盛放产品的容器(匡)
 * 1.生产者生成完产品之后将产品放入容器中,如果容器满了,停止生产并通知消费者进行消费
 * 2.消费者从容器中取出产品进行消费,如果容器空了,停止消费并通知生产者者进行生成
 *  
 * @author Administrator
 *
 */
public class SyncStack {
    int index=0;//执行馒头的存储位置
    SteamBread[] sb = new SteamBread[6];//容器
    /**
     * 入栈:将生成者生成的馒头保存到匡中
     */
    public synchronized void push(SteamBread s){
        //判断匡是否已满
        if(index==sb.length-1){
            try {
                this.wait();//停止生产
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        this.notify();//唤醒消费者线程进行消费
        //将馒头添加到匡中
        sb[index++]=s;
    }
    
    /**
     * 出栈:消费者从匡中获取馒头
     * @return
     */
    public synchronized SteamBread pop(){
        if(index==0){
            try {
                this.wait();//停止消费
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        this.notify();//唤醒生成者进行生产
        this.index--;//push第n个之后,this.index++,使栈顶为n+1,故return之前要减一
        return sb[index];
    }
}
/*
*
 生产者
 * @author Administrator
 *
 */
public class Producer implements Runnable{
    SyncStack ss;//
    public Producer(SyncStack ss) {
        this.ss=ss;
    }
    
    @Override
    public void run() {
        for(int i=1;i<20;i++){
            System.out.println("生产者开始生产---->");
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            SteamBread s = new SteamBread(i);
            System.out.println("生产了:"+s);
            ss.push(s);
            
        }
    }

}
/**
 * 消费者
 * @author Administrator
 *
 */
public class Consume implements Runnable{
    SyncStack ss;//
    public Consume(SyncStack ss) {
        this.ss=ss;
    }
    
    @Override
    public void run() {
        for(int i=1;i<20;i++){
            System.out.println("消费者开始消费---->");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            SteamBread s = ss.pop();
            System.out.println("消费者拿走了---->"+s+"号馒头");
        }
    }

}
public class Test {
    public static void main(String[] args) {
        SyncStack ss = new SyncStack();
        Producer producer = new Producer(ss);
        Consume consume = new Consume(ss);
        Thread t = new Thread(producer);
        Thread t2 = new Thread(consume);
        t.start();
        t2.start();
    }
}

 

posted @ 2017-06-19 10:03  咫尺天涯是路人丶  阅读(1639)  评论(0编辑  收藏  举报