zoukankan      html  css  js  c++  java
  • 线程

    线程
    2019-11-1414:44:18
     
    /**
     * 程序 : 保存在硬盘上的一段可执行的静态代码的集合(是可执行文件)
     * 进程 : 一段正在内存中运行中的程序(有生命周期), 进程之间不可以直接互访.
     * 线程 : 一个进程中的多个子任务, 直接由CPU负责处理执行. 多线程之间可以方便的共享数据
     *
     * 线程启动第一种方式, 实现的方式
     * 1) 写一个具体类, 实现Runnable接口, 并实现接口中的抽象方法run, 这个方法就是线程体
     * 2) 创建这个具体类的对象, 并以它为实参再创建Thread类的对象, 就是线程对象
     * 3) 调用线程对象的start方法, 启动线程, 具体类中的run方法就会被调用执行.
     *
     * 线程启动第二种方式, 继承的方式
     * 1) 写一个具体类, 继承Thread类, 必须重写run方法, 因为父类中的run方法什么也没有做
     * 2) 创建这个具体类对象, 相当于创建了线程对象
     * 3) 调用此线程对象的start方法, 启动线程.
     *
     * 多线程程序的优点:
     提高应用程序的响应。对图形化界面更有意义,可增强用户体验。
     提高计算机系统CPU的利用率
     改善程序结构。将既长又复杂的进程分为多个线程,独立运行,利于理解和修改
     
      生命周期 :
                 阻塞(sleep, join, wait...) 
               |     |
               |  失去CPU执行权 |
     新建(new Thread()) -> 就绪(start()) <--------------- |      正常或异常结束run
              ---------------> 运行-----------------------> 死亡
              获得CPU执行权
     
     线程同步 : 多个线程 "同时" 修改 "同"一个数据
     
     */
    class MyThread extends Thread {
     
     @Override
     public void run() {
      for (int i = 0; i < 100; i++) {
       System.out.println(Thread.currentThread().getName() + " : " + i);
      }
     }
    }
    public class ThreadTest {
     
     public static void main(String[] args) {
      Thread myThread = new MyThread(); // 相当于建栈
      myThread.start(); // 激活栈, 把run压入
      
      try {
       myThread.join(); // 主线程阻塞, 子线程执行, 子线程执行完, 主线程才继续.
      } catch (InterruptedException e) {
       e.printStackTrace();
      }
      
      for (int i = 0; i < 100; i++) {
       System.out.println(Thread.currentThread().getName() + " : " + i);
      }
     }
    }
     

    一、创建并启动一个线程的方法

      1)实现接口的方式

        ① 写一个具体类, 实现Runnable接口, 并实现其中的run方法,这个run方法就是线程的入口方法
              ② 创建这个类的对象, 并以这个对象为实参, 创建Thread类的对象
             ③ 调用Thread对象的start()方法 启动线程

    public class ExerRunner implements Runnable {
        
        //1 创建一个子线程,在线程中输出1-100之间的偶数,主线程输出1-100之间的奇数。
        private int count = 1;
    
        @Override
        public void run() {
            for (; count < 100; count++) {
                if (count % 2 == 0) {
                    System.out.println(Thread.currentThread().getName() + " : " + count);
                }
            }
        }
    }
    
    
    public class ExerRunnerTest {
        
        public static void main(String[] args) {
            //1 创建一个子线程,在线程中输出1-100之间的偶数,主线程输出1-100之间的奇数。
            Runnable exerRunner = new ExerRunner();
            Thread thread = new Thread(exerRunner);
            thread.start();
            
            for (int i = 0; i < 100; i++) {
                if (i % 2 != 0) {
                    System.out.println(Thread.currentThread().getName() + " : " + i);
                }
            }
        }
    }

     二、同时 创建俩个 子线程

    public class HelloRunner implements Runnable {
        
        private int i;
    
        @Override
        public void run() {
            for (i = 0; i < 100; i++) {
                System.out.println(Thread.currentThread().getName() + "** " + i); // 哪个栈压入此方法, 就获取哪个栈
            }
        }
        
        
    }
    
    
    public class HelloRunner2 implements Runnable {
    
        @Override
        public void run() {
            for (int i = 0; i < 100; i++) {
                System.out.println(Thread.currentThread().getName() + "## " + i);
            }
        }
    
    }
    
    
    
    public class HelloRunnerTest {
        
        public static void main(String[] args) {
            //  1) 写一个具体类, 实现Runnable接口, 并实现接口中的抽象方法run, 这个方法就是线程体
            //* 2) 创建这个具体类的对象, 并以它为实参再创建Thread类的对象, 就是线程对象
            Runnable runner = new HelloRunner();
            Thread thread = new Thread(runner); // 执行此操作时在内部创建一个栈.
            thread.setName("子线程");
            //* 3) 调用线程对象的start方法, 启动线程, 具体类中的run方法就会被调用执行.
            thread.start(); // 两个动作, 1) 激活栈, 2) 把run压入栈底, 马上结束返回
            //thread.run(); run只是普通方法调用
            
            Thread thread2 = new Thread(runner);
            thread2.start();
            
            //Thread.currentThread().setName("主线程");
            
            // 启动另一个子线程
            Runnable helloRunner2 = new HelloRunner2();
            Thread thread3 = new Thread(helloRunner2);
            thread3.start();
        }
    }

     三、以通知的方式停止线程

    public class StopRunner implements Runnable {
    
        private int count = 0;
        private boolean runFlag = true;
        
        public void setRunFlag(boolean runFlag) {
            this.runFlag = runFlag;
        }
        
        public boolean isRunFlag() {
            return runFlag;
        }
        
        //在main方法中创建并启动1个线程。线程循环随机打印100以内的整数,直到主线程从键盘读取了“Q”命令。
    
        @Override
        public void run() {
            while (runFlag) {
                System.out.println(Thread.currentThread().getName() + " : " + count++);
                if (count == 100) {
                    count = 0;
                }
            }
            System.out.println("关键代码");
        }
        
    }
    
    
    public class StopRunnerTest {
        
        public static void main(String[] args) {
            Runnable stopRunner = new StopRunner();
            Thread thread = new Thread(stopRunner);
            thread.start();
            
            int j = 0;
            for (int i = 0; i < 10000000; i++) {
                j++;
            }
            
            //thread.stop(); // 这个方法禁止使用, 因为它太暴力了!!!!
                    // 用 多态的方式
            ((StopRunner)stopRunner).setRunFlag(false); // 以通知的方式停止线程
            
            
        }
    }
     

    四、

    //在main方法中创建并启动1个线程。线程循环随机打印100以内的整数,直到主线程从键盘读取了“Q”命令。
    public class ExerStopRunner implements Runnable {
        
        private boolean runFlag = true;
        
        public void setRunFlag(boolean runFlag) {
            this.runFlag = runFlag;
        }
        
        @Override
        public void run() {
            while (runFlag) {
                System.out.println(Thread.currentThread().getName() + " : " + (int)(Math.random() * 100));
            }
            System.out.println("关键代码");
        }
        
        
    }
    
    
    public class ExerSleepRunnerTest {
        
        public static void main(String[] args) {
            Runnable runner = new ExerSleepRunner();
            Thread thread = new Thread(runner);
            thread.start();
            
            // 不断地观察loopFor的值
            while (true) {
                if (((ExerSleepRunner)runner).isLoopOver()) {
                    break;
                }
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            
            thread.interrupt();
        }
    }

    五、睡眠的几种解除方式

     线程调用sleep方法后, 会使调用者线程进入睡眠状态, 不会抢夺CPU... 直到解除阻塞为止
     线程进入sleep后, 几种解除方式 :
       1) 时间到了, 自然醒

      2) 被别的线程打断, 调用本线程对象的interrupt(), 被打断的线程会抛出异常

    public class SleepRunner implements Runnable {
    
        @Override
        public void run() {
            for (int i = 0; i < 100; i++) {
                int n = (int)(Math.random() * 200);
                System.out.println(n);
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    System.out.println("被打断了....");
                } 
            }
            System.out.println("for循环结束了");
            
            try {
                Thread.sleep(30 * 1000);
            } catch (InterruptedException e) {
                System.out.println("在睡30秒时被打断");
            }
            
            System.out.println("子线程OVER");
        }
        
    }
    
    
    public class SleepRunnerTest {
        
        public static void main(String[] args) {
            Runnable runner = new SleepRunner();
            Thread thread = new Thread(runner);
            thread.start();
            
            System.out.println("main方法");
            
            try {
                Thread.sleep(21 * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            
            thread.interrupt();
            
        }
    }

    六、

    /**编写程序,在main方法中创建一个线程。线程每隔一定时间(200ms以内的随机时间)产生一个0-100之间的随机整数,
    打印后将该整数放到集合中;
    共产生100个整数,全部产生后,睡眠30秒,然后将集合内容打印输出;
    在main线程中,唤醒上述睡眠的线程,使其尽快打印集合内容。*/

    public class ExerSleepRunner implements Runnable {
        
        private boolean loopOver = false;
        
        public boolean isLoopOver() {
            return loopOver;
        }
        
        @Override
        public void run() {
            List<Integer> list = new ArrayList<Integer>();
            for (int i = 0; i < 100; i++) {
                int n = (int)(Math.random() * 100);
                System.out.println(n);
                list.add(n);
                
                int randTime = (int)(Math.random() * 200);
                try {
                    Thread.sleep(randTime);
                } catch (InterruptedException e) {
                    System.out.println("在睡" + randTime + "毫秒时被打断");
                }
            }
            loopOver = true;
            
            System.out.println("我要睡30秒了.....");
            try {
                Thread.sleep(30 * 1000);
            } catch (InterruptedException e) {
                System.out.println("在长睡时被打断, 严重不爽");
            }
            
            System.out.println("我要打印集合了.....");
            Iterator<Integer> iterator = list.iterator();
            while (iterator.hasNext()) {
                Integer next = iterator.next();
                System.out.println(next);
            }
        }
            
    }
    
    
    
    public class ExerSleepRunnerTest {
        
        public static void main(String[] args) {
            Runnable runner = new ExerSleepRunner();
            Thread thread = new Thread(runner);
            thread.start();
            
            // 不断地观察loopFor的值
            while (true) {
                if (((ExerSleepRunner)runner).isLoopOver()) {
                    break;
                }
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            
            thread.interrupt();
        }
    }

    七、

    *******

    通过构造器 对象关联

    必须在线程启动前设置守护线程

    守护线程特点 : 如果没有了用户线程, 所有守护线程自动终止.

    在main方法中创建并启动1个线程。线程循环随机打印100以内的整数,直到主线程从键盘读取了“Q”命令。

    import java.io.BufferedReader;
    import java.io.InputStreamReader;
    
    public class KeyListener implements Runnable {
    
        private Runnable runner;
        
        public KeyListener(Runnable runner) {
            super();
            this.runner = runner;
        }
    
        @Override
        public void run() {
            BufferedReader bufferedReader = null;
            try {
                bufferedReader = new BufferedReader(new InputStreamReader(System.in));
                String line = bufferedReader.readLine();
                while (line != null) {
                    // 处理数据
                    if (line.equalsIgnoreCase("q")) {
                        // 停止子线程
                        ((ExerStopRunner)runner).setRunFlag(false);
                        //break; // 自我终结
                    }
                    // 继续读
                    line = bufferedReader.readLine();
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (bufferedReader != null) {
                    try {
                        bufferedReader.close();
                    } catch (Exception e2) {
                    }
                }
            }
        }
    
    }
    
    
    public class ExerStopRunnerTest {
        
        public static void main(String[] args) {
            //在main方法中创建并启动1个线程。线程循环随机打印100以内的整
            Runnable runner = new ExerStopRunner();
            Thread thread = new Thread(runner);
            thread.start();
            
            //在main方法中创建并启动两个线程。第一个线程循环随机打印100以内的整数,直到第二个线程从键盘读取了“Q”命令。
            Runnable runner2 = new KeyListener(runner); // 通过构造器 对象关联
            Thread thread2 = new Thread(runner2);
            // 必须在线程启动前设置守护线程
            thread2.setDaemon(true); // 守护线程特点 : 如果没有了用户线程, 所有守护线程自动终止.
            thread2.start();
            
        } 
    }

     八 、线程的互斥锁

    public class Counter implements Runnable {
        
        private int counter = 200;
        private Object object = new Object();
        
        @Override
        //public synchronized void run() {// 粒度太大, 不好
        public void run() {
            //synchronized (this) { // 粒度太大, 不好
                for (int i = 0; i < 50; i++) {
                    synchronized ("") { // 互斥锁对象, 下面的代码就会只在某一个线程中执行, 其他线程想执行下面的代码, 必须要等待.
                        // 具有原子性的代码, 具有不可分割性
                        counter -= 2;
                        try {
                            Thread.sleep(10);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName() + " : " + counter);
                    }
                }
            //}
        }
    
    }
    
    public class CounterTest {
        
        public static void main(String[] args) {
            Runnable runner = new Counter();
            
            Thread thread1 = new Thread(runner);
            thread1.setName("子线程1");
            thread1.start();
            
            Thread thread2 = new Thread(runner);
            thread2.setName("子线程2");
            thread2.start();
        }
    }

    九、银行账户

    银行有一个账户Account包含属性name, balance
    写一个普通 类Deposit实现Runnable, 在run方法中存钱
    有两个柜台(线程)分别同时向同一个账户存3000元,每次存1000,存3次。每次存完打印账户余额。睡眠10毫秒
    问题:该程序是否有安全问题,如果有,如何解决?
    扩展练习 :
    一个柜台Deposit存3000元, 每次存1000,存3次
    另一个柜台Withdraw取3000元, 每次取1000,取3次
    【提示】
    1,明确哪些代码是多线程运行代码,须写入run()方法
    2,明确什么是共享数据。
    3,明确多线程运行代码中哪些语句是操作共享数据的。
     
    public class RunnerDeposit implements Runnable{
        private Account account;
        public RunnerDeposit(Account account) {
            this.account=account;
        }
        private double money;
        //Account account=new Account();
        @Override
        public void run() {
            for (int i = 0; i < 3; i++) {
                synchronized ("") {
                    money = account.getBalance();
                    account.setBalance(money+1000);
                    //balance+=money;
                    //余额
                    System.out.println(Thread.currentThread().getName()+"刚刚存了1000元");
                    //余额
                    System.out.println("账户余额:"+account.getBalance()+"元");
                    
                    System.out.println();
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        System.out.println("存钱中,请勿打扰...!");
                    }
                }
                
            }
            
        }
    }
    
    public class RunnerWithdraw implements Runnable{
        private Account account;
        public RunnerWithdraw(Account account) {
            this.account=account;
        }
        private double money;
        @Override
        public void run() {
            
            for (int i = 0; i < 3; i++) {
                synchronized ("") {
                    money = account.getBalance();
                    account.setBalance(money-1000);
                    System.out.println(Thread.currentThread().getName()+"刚刚取了1000元");
                    //余额
                    System.out.println();
                    System.out.println("账户余额:"+account.getBalance());
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        System.out.println("取钱中,请勿打扰...!");
                    }
                 }
                
            }
        }
    
    }
    
    public class RunnerAccountMain {
        public static void main(String[] args) {
             Account account = new Account("张三", 0);
            Runnable runnerDeposit = new RunnerDeposit(account);
            Thread account1 = new Thread(runnerDeposit);
            account1.setName("柜台1:");
            account1.start();
            
            Thread account2 = new Thread(runnerDeposit);
            account2.setName("柜台2:");
            account2.start();
            
            Runnable runnerWithdraw = new RunnerWithdraw(account);
            Thread account3 = new Thread(runnerWithdraw);
            account3.setName("柜台3:");
            
            account3.start();
            
            
        }
    }
  • 相关阅读:
    查看邵杨的源码
    java 读写excle
    绘图的引擎
    handler的使用
    小结
    周末,啦啦啦
    监控宝发布移动应用监控服务 引领移动APM
    监控宝优化升级 创新驱动用户体验
    云智慧:顺势而为 做世界级APM服务商
    性能为王:云智慧APM助小米IT服务能力提升
  • 原文地址:https://www.cnblogs.com/SGRBOY/p/11856760.html
Copyright © 2011-2022 走看看