程序员首页投稿(暂停使用,暂停投稿)技术干货

Java 复习之多线程

2017-12-02  本文已影响92人  maoqitian

/**
 * 
 * @author 毛麒添
 * 多线程程序实现的方式1 继承Thread
 */
public class Demo_Thread {

    public static void main(String[] args) {
        MyTread mythread=new MyTread();
        mythread.start();//必须调用start方法 子线程才能跑起来
        for (int i = 0; i < 1000; i++) {
            System.out.println("主线程运行了");
        }
    }

}
 
class MyTread extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            System.out.println("子线程运行了");
        }
    }
}
/**
 * 
 * @author 毛麒添
 * 多线程程序实现的方式2 继承Runnable接口
 */
public class Demo_Runnable {

    public static void main(String[] args) {
        MyRunnable mr=new MyRunnable();
        
        new Thread(mr).start();//将Runnable传入Thread中启动线程 ,因为Runnable接口中没有start()方法
        
        for (int i = 0; i < 1000; i++) {
            System.out.println("主线程运行了");
        }
    }
}
class MyRunnable implements Runnable{

    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            System.out.println("子线程运行了");
        }   
    }
}
 private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize, AccessControlContext acc) {
      
    ...................
        this.target = target;
    ..................
    }


 @Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }

init()方法中将我们传入的Runnable传递给了成员变量target,最终执行的还是Thread的run()方法 , 所以由此我们可以想到,Runnable接口其实是对于Thread类的补充,当我们一个要实现子线程类已经继承了一个类,由于Java的单继承性质,该类就可以通过实现Runnable接口来实现多线程。

//匿名内部类实现多线程 Thread
        new Thread(){public void run() {
            for (int i = 0; i < 1000; i++) {
                System.out.println("匿名内部类实现了多线程 Thread");
            }
        };}.start();
        
//匿名内部类实现多线程 Runnable
        new Thread(new Runnable() { 
            @Override
            public void run() {
                for (int i = 0; i < 1000; i++) {
                    System.out.println("匿名内部类实现了多线程 Runnable");
                }   
            }
        }).start();
/**
 * 
 * @author 毛麒添
 * 获取当前线程并给其设置名字
 */
public class GetCurrentThread {
    public static void main(String[] args) {
        //获取主线程
        Thread.currentThread().setName("我是主线程");
        System.out.println(Thread.currentThread().getName());
        
        //获取子线程并给其设置名字 Thread
        new Thread("我是子线程1"){public void run() {
            System.out.println(getName());
        };}.start();
        
        //获取子线程并给其设置名字 Runnable
        new Thread(new Runnable() {
            @Override
            public void run() {
                //runnable 
                Thread.currentThread().setName("我是子线程2");
            System.out.println(Thread.currentThread().getName());   
            }
        }).start();
    }
}

运行结果:


获取当前线程.png

线程休眠我们可以使用Thread的静态方法sleep(long millis),该方法在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),指定的休眠时间过了之后线程会自动恢复执行。

/**
 * @author 毛麒添
 * 模拟CPU执行两个线程任务
 */
public class Sleep_Thread {

    public static void main(String[] args) {
        
        new Thread("线程1"){
            public void run() {
                for (int i = 0; i < 5; i++) {
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    System.out.println(getName()+"执行了");
                }
            };
        }.start();
        
        new Thread("线程2"){
            public void run() {
                for (int i = 0; i < 5; i++) {
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    System.out.println(getName()+"执行了");
                }
            };
        }.start();

    }
}

运行结果:


休眠线程程序运行截图.png

setDaemon(boolean b), 设置一个线程为守护线程, 该线程不会单独执行, 当其他非守护线程都执行结束后, 自动退出,你可能看完这句话还是不知道什么是守护线程,下面看一个模拟QQ程序关闭的例子

/**
 * @author 毛麒添
 * 当我们使用QQ聊天的时候,如果关闭QQ 则所有的聊天窗口也会关闭
 */
public class ThreadDaemon {

    public static void main(String[] args) {
        Thread thread1 = new Thread("QQ非守护线程"){
            @Override
            public void run() {
                for (int i = 0; i < 2; i++) {
                    System.out.println(getName()+"正在运行");
                }
                System.out.println("QQ程序关闭了");
            }
        };
        Thread thread2 = new Thread("QQ守护线程(聊天窗口)"){
            @Override
            public void run() {
                for (int i = 0; i < 50; i++) {
                    System.out.println(getName()+"正在运行");
                }
            }
        };
        thread2.setDaemon(true);//设置守护线程
        thread1.start();
        thread2.start();
    }
}

运行结果:


守护线程程序运行截图.png

从程序结果我们可以这样理解,正在运行的QQ程序为非守护线程,而我们的聊天窗口为守护线程,不管你有多少个聊天窗口,只要非守护线程QQ程序关闭,我们聊天窗口也会随之关闭,运行截图中QQ程序关闭之后还运行了几次守护线程是因为守护的线程的关闭需要缓冲,就相当于你要打电话给一个人,拨打号码和等待对方接听也是需要一定的时间。

/**
 * 
 * @author 毛麒添
 * 加入线程(插队)
 */

public class ThreadJoin {

    public static void main(String[] args) {
        Thread thread1 = new Thread(){
            @Override
            public void run() {
                for (int i = 0; i < 5; i++) {
                    System.out.println(getName()+"正在运行"+i);
                }
            }
        };
        Thread thread2 = new Thread(){
            @Override
            public void run() {
                for (int i = 0; i < 5; i++) {
                    if(i%2==0){
                        try {
                            //thread1.join();//插队,加入
                            thread1.join(30);//插队,有固定的时间,过了固定时间,继续交替执行
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                    System.out.println(getName()+"正在运行"+i);
                }
            }
        };
        
        
        thread1.start();
        thread2.start();
    }
}
/**
 * 
 * @author 毛麒添
 * 同步代码块
 */
public class Thread_sync {
    public static void main(String[] args) {
        Printer p=new Printer();
        new Thread(){public void run() {
            while(true){
                p.print1(); 
            }   
        };}.start();
        new Thread(){public void run() {
            while(true){
                p.print2(); 
            }
        };}.start();
    }
}

class Printer {
     static Object b=new Object();//锁对象可以是任意对象
    public static void print1() {
        synchronized(b){                //锁对象可以是任意对象,但是被锁的代码需要保证是同一把锁,不能用匿名对象
            System.out.print("今");
            System.out.print("晚");
            System.out.print("吃");
            System.out.print("鸡");
            System.out.println();
        }
    }

    public static void print2() {       
        synchronized(b){    
            System.out.print("我");
            System.out.print("怕");
            System.out.print("是");
            System.out.print("送");
            System.out.print("快");
            System.out.print("递");
            System.out.println();
        }
    }
}

例子程序中如果不对代码块加入synchronized关键字,则会出现某段代码块没有执行完,如图


代码不同步则会出现代码块没有执行完.png
class Printer {
     //static Object b=new Object();//锁对象可以是任意对象
    public static void print1() {
        synchronized(Printer.class){                //锁对象可以是任意对象,但是被锁的代码需要保证是同一把锁,不能用匿名对象
            System.out.print("今");
            System.out.print("晚");
            System.out.print("吃");
            System.out.print("鸡");
            System.out.println();
        }
    }
    public static synchronized void print2() {          
            System.out.print("我");
            System.out.print("怕");
            System.out.print("是");
            System.out.print("送");
            System.out.print("快");
            System.out.print("递");
            System.out.println();
    }
}
/**
 * 
 * @author 毛麒添
 * 一趟火车有100张票 分四个窗口卖完 (Thread实现)
 */
public class Ticket_thread {

    public static void main(String[] args) {

        Ticket t1=new Ticket();
        Ticket t2=new Ticket();
        Ticket t3=new Ticket();
        Ticket t4=new Ticket();
        
        t1.setName("火车售票窗口1");
        t2.setName("火车售票窗口2");
        t3.setName("火车售票窗口3");
        t4.setName("火车售票窗口4");
        
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}

class Ticket extends Thread{
    
    private static int tickets=100;
    @Override
    public void run() {
        
            while(true){
                synchronized (Ticket.class) {//锁对象必须使用线程类本身,保证处理的是同一个数据
                if(tickets <= 0){
                    break;
                }
                try {
                    Thread.sleep(6);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println(getName()+":这是第"+tickets--+"号票卖出");
            }
        }
        
    }
}

/**
 * @author 毛麒添
 * 一趟火车有100张票 分四个窗口卖完 (Runnable实现)
 */
public class Ticket_Runnable {

    public static void main(String[] args) {
        Ticketrn tn=new Ticketrn();
        Thread t1 = new Thread(tn);
        Thread t2=new Thread(tn);
        Thread t3=new Thread(tn);
        Thread t4=new Thread(tn);
        
        t1.setName("火车售票窗口1");
        t2.setName("火车售票窗口2");
        t3.setName("火车售票窗口3");
        t4.setName("火车售票窗口4");
        
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }

}
class Ticketrn implements Runnable{
    
    private  int tickets=100;
    @Override
    public void run() {
        
            while(true){
                synchronized (this) {//只需要把runnable对象传给Thread,都是本身对象,传递的锁对象无所谓,都可以保证操作的是同一个数据
                if(tickets <= 0){
                    break;
                }
                try {
                    Thread.sleep(6);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+":这是第"+tickets--+"号票卖出");
            }
        }
    }
}

上面例子我们用程序表示:

/** 
 * @author 毛麒添
 * 死锁问题
 */
public class Thread_deadlock {
    private static String s1="西路";
    private static String s2="南路";
    private static String s3="东路";
    private static String s4="北路";
public static void main(String[] args) {    
        new Thread("西路车"){
            public void run() {
                while(true){
                    synchronized (s1) {
                    System.out.println(getName()+":进入"+s1 );
                    synchronized (s2) {
                        System.out.println(getName()+"等待"+s2+"车");  
                    }
                  }
                }
            };
        }.start();
        new Thread("南路车"){
            public void run() {
                while(true){
                    synchronized (s2) {
                    System.out.println(getName()+":进入"+s2 );
                    synchronized (s3) {
                        System.out.println(getName()+"等待"+s3+"车");  
                      }
                    }
                }
            };
        }.start();
        new Thread("东路车"){
            public void run() {
                while(true){
                    synchronized (s3) {
                    System.out.println(getName()+":进入"+s3 );
                    synchronized (s4) {
                        System.out.println(getName()+"等待"+s4+"车");  
                    }
                  }
                }
            };
        }.start();
        new Thread("北路车"){
            public void run() {
                while(true){
                    synchronized (s4) {
                    System.out.println(getName()+":进入"+s4 );
                    synchronized (s1) {
                        System.out.println(getName()+"等待"+s1+"车");  
                    }
                  }
               }
            };
        }.start();
    }
}
死锁例子运行截图.png

由上程序运行截图我们可以看出,程序还在运行,但是无法继续执行,已经出现死锁,所以当我们使用同步代码块的时候,一定不要让同步代码块嵌套,也就不会发生死锁的情况

该类也就是我们常说的定时器,他的构造需要传入一个定时任务TimerTask,该类是一个抽象类,实现了Runnable接口,我们可以继承TimerTask这个类并在 run() 方法中做我们需要定时的操作,最后由Timer.schedule() 来实现我们定时操作

/**
 * 
 * @author 毛麒添
 * Timer 应用
 */
public class Demo_Timer {
    public static void main(String[] args) {    
        Timer timer=new Timer();
        //从现在开始,每三秒响一次闹铃
        timer.schedule(new MyTimer(),new Date(System.currentTimeMillis()),3000);

    }
}
class MyTimer extends TimerTask{
    @Override
    public void run() {
        System.out.println("大懒虫,起床啦");  
    }   
}
/**
 * @author 毛麒添
 * 等待唤醒机制  两个线程交替执行
 */
public class Two_Thread_call {
        public static void main(String[] args) {
            Printer p=new Printer();
            new Thread(){public void run() {
                while(true){
                    try {
                        p.print1();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    } 
                }   
            };}.start();
            new Thread(){public void run() {
                while(true){
                    try {
                        p.print2();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    } 
                }
            };}.start();
        }
    }
    class Printer {
        private boolean flag=true;
        public void print1() throws InterruptedException {
            synchronized(this){
                if(!flag){
                    this.wait();  //当前线程进入等待
                }
                System.out.print("今");
                System.out.print("晚");
                System.out.print("吃");
                System.out.print("鸡");
                System.out.println();
                flag=false;
                this.notify();   //随机唤醒单个等待的线程
            }
        }
        public  void print2() throws InterruptedException {       
            synchronized(this){
                if(flag){
                    this.wait();
                }
                System.out.print("我");
                System.out.print("怕");
                System.out.print("是");
                System.out.print("送");
                System.out.print("快");
                System.out.print("递");
                System.out.println(); 
                flag=true;
                this.notify();
            }
        }
    }

运行结果:

两个线程通信运行结果.png
class Printer2 {
    private int flag=1;
    public void print1() throws InterruptedException {
        synchronized(this){
            while(flag!=1){
                this.wait();  //当前线程进入等待
            }
            System.out.print("今");
            System.out.print("晚");
            System.out.print("吃");
            System.out.print("鸡");
            System.out.println();
            flag=2;
            this.notifyAll();  //随机唤醒单个等待的线程
        }
    }
    public  void print2() throws InterruptedException {       
        synchronized(this){
            while(flag!=2){
                this.wait();
            }
            System.out.print("我");
            System.out.print("怕");
            System.out.print("是");
            System.out.print("送");
            System.out.print("快");
            System.out.print("递");
            System.out.println(); 
            flag=3;
            this.notifyAll();
        }
    }
    public  void print3() throws InterruptedException {       
        synchronized(this){
            while(flag!=3){
                this.wait();
            }
            System.out.print("那");
            System.out.print("我");
            System.out.print("就");
            System.out.print("当");
            System.out.print("医");
            System.out.print("疗");
            System.out.print("兵");
            System.out.println(); 
            flag=1;
            this.notifyAll();
        }
    }
}

小结

class Printer3 {
    private int flag=1;
    private ReentrantLock rtl =new ReentrantLock();
    private Condition c1=rtl.newCondition();
    private Condition c2=rtl.newCondition();
    private Condition c3=rtl.newCondition();    
    public void print1() throws InterruptedException {
        rtl.lock();         //获取锁
        if(flag!=1){
            c1.await();
        }
            System.out.print("今");
            System.out.print("晚");
            System.out.print("吃");
            System.out.print("鸡");
            System.out.println();
            flag=2;
            c2.signal();
            rtl.unlock(); //释放锁      
    }
    public  void print2() throws InterruptedException {       
        rtl.lock();
            if(flag!=2){
                c2.await();
            }
            System.out.print("我");
            System.out.print("怕");
            System.out.print("是");
            System.out.print("送");
            System.out.print("快");
            System.out.print("递");
            System.out.println(); 
            flag=3;
            c3.signal();
           rtl.unlock();
    }
    public  void print3() throws InterruptedException {       
        rtl.lock();
            if(flag!=3){
                c3.await();
            }
            System.out.print("那");
            System.out.print("我");
            System.out.print("就");
            System.out.print("当");
            System.out.print("医");
            System.out.print("疗");
            System.out.print("兵");
            System.out.println(); 
            flag=1;
            c1.signal();
           rtl.unlock();
    }
}

线程池描述

/**
 * @author 毛麒添
 * JDK 1.5 Executor
 */
public class MyExecutorService {

    public static void main(String[] args) {
        //创建线程池 
        ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(2);
        
        newFixedThreadPool.submit(new MyRunnable()); //将线程放入线程池
        newFixedThreadPool.submit(new MyRunnable());
        
        newFixedThreadPool.shutdown();//关闭线程池
        
    }

}

class MyRunnable implements Runnable{

    @Override
    public void run() {
        // TODO Auto-generated method stub
        
    }
    
}
/**
 * Created by 毛麒添 on 2017/2/10 0010.
 * 线程管理类,线程池为单例
 */
public class ThreadManager {
    private static ThreadPool mThreadPool;

    public static ThreadPool getmThreadPool(){
        if (mThreadPool==null){
            synchronized (ThreadManager.class){
                if(mThreadPool==null){//线程安全
                    mThreadPool=new ThreadPool(10,10,1L);
                }
            }
        }
        return mThreadPool;
    }
    //线程池
    public static class ThreadPool{

        private int corePoolSize;//核心线程数 10
        private int maximumPoolSize;//最大线程数 10
        private long keepAliveTime;//线程休眠时间 1秒

        private ThreadPoolExecutor executor;

        private ThreadPool(  int corePoolSize, int maximumPoolSize,long keepAliveTime){
              this.corePoolSize=corePoolSize;
              this.maximumPoolSize=maximumPoolSize;
              this.keepAliveTime=keepAliveTime;
        }


        public void execute(Runnable runnable){
            /**
             * int corePoolSize, 核心线程数
             * int maximumPoolSize, 最大线程数
             * long keepAliveTime, 线程休眠时间
             * TimeUnit unit, 时间单位
             * BlockingQueue<Runnable> workQueue, 线程队列
             * ThreadFactory threadFactory, 生成线程的工厂
             * RejectedExecutionHandler handler 线程一次处理
             */
            if(executor==null){
                executor = new ThreadPoolExecutor(corePoolSize,maximumPoolSize,keepAliveTime,
                        TimeUnit.SECONDS,new LinkedBlockingQueue<Runnable>(),
                        Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());
            }
            executor.execute(runnable);
        }
        //取消任务,从任务队列中将其移除
        public void cancelTask(Runnable runnable){
            if(runnable!=null){
                executor.getQueue().remove(runnable);
            }
        }
    }
}
//该类使用
 ThreadManager.getmThreadPool().execute(new Runnable() {
                @Override
                public void run() {
                  //执行耗时操作   
                }
            });

最后

好记性不如烂笔头,我希望通过这一篇文章,可以在我忘记了一下基础知识的时候,通过看一下这个复习笔记,找回忘掉的知识,如果你看到这篇文章,也希望可以帮助到你。文章中如果有错误,请大家给我提出来,大家一起学习进步,如果觉得我的文章给予你帮助,也请给我一个喜欢或者关注。

本系列其他文章:
Java复习之集合框架
Java复习之IO流(上)
Java复习之IO流(下)
Java 复习之多线程

上一篇下一篇

猜你喜欢

热点阅读