zoukankan      html  css  js  c++  java
  • Java多线程

    多线程和多进程的区别:

      本质的区别在于每隔进程拥有自己的一整套变量,而线程则共享数据.在有些操作系统中,与进程相比较,线程更轻量级,创建,撤销一个线程比启动新进程的开销要小的多.

      简单的来说:一个进程至少有一个线程,线程是进程的组成部分,线程结束,进程不一定结束,进程结束,线程一定结束.

    为什么要使用线程?

      使用线程是为了给其他任务提供运行的机会.在普通的程序中,只能顺序执行每一个任务,使用线程可以在一个任务未完成时执行其他的任务,

    如何实现线程?

      [1].继承Thread类或者实现Runnable接口.

      [2].重写run方法.

      [3].调用run方法(切记使用 对象.start()(来启动新的线程) 来调用,不能直接调用run方法).

      在继承Thread类和实现Runnable接口的调用run方法也是不同的,前者直接是对象.start()(new 对象().start()),后者是利用Thread类的对象来调用start的方法(也就是new Thread(new 对象()).start()).

    线程的状态:

      New(新创建),Runnable(可运行),Blocked(被阻塞),Waiting(等待),Timed waiting(计时等待),Terminated(被终止),

      新创建是指使用new操作符创建一个新线程,还没有运行.

      可运行是指调用了start的方法,处于Runnable状态,这个线程可能正在运行,也可能没在运行,这取决于操作系统给线程提供运行的时间.

      当一个线程试图获取一个内部的对象锁,而该锁被其它线程持有,则该线程进入阻塞状态,直到线程调度器允许该线程持有这个对象锁的时候.

      当线程等待另一个线程通知调度器一个条件时,他自己进入等待状态.简单的来说等待另一个线程释放他所需要的资源的过程.

      Thread.sleep,Object.wait,Thread.join,Lock.tryLock以及Condition.await是带有超时参数的方法,调用他们将导致线程进入计时等待.

      被终止的线程:(1).由于run方法的正常退出而自然死亡,(2).因为一个没有捕获的异常终止了run方法而意外死亡.

      获取线程的状态:对象.getState().

    线程的属性:

      [1].优先级(1~10):MIN_PRIORITY(1),MAX_PRIORITY(10),NORM_PRIORITY(5).线程的优先级是高度依赖于系统的,线程调度器有机会选择新线程的时候,首先选择具有较高优先级的线程.

      [2].守护线程:t.setDaemon(true)将一个线程转化为守护线程(必须在线程启动前调用),守护线程的唯一用途是为其他线程提供服务的.

      [3].未捕获异常处理器(暂时不懂,以后懂了再补充).

    线程是为了给其他线程运行的机会,这样的话程序有可能需要同步,那么同步就会带来读脏数据的问题,也就是共享数据的问题,这提供两种方法解决该问题,但建议使用第二种方法.

      [1]:锁对象(ReentrantLock)和条件对象(Condition):

        使用代码来说明(利用银行转钱的例子来说明):

    package book_14.synch;

    import java.util.Arrays;
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;

    /**
     * 同步(使用锁对象和条件对象)
     * @author Administrator
     *
     */
    public class Bank {
        
        private final double[] accounts; // 银行账户的数量
        private Lock bankLock; // 创建锁对象
        private Condition sufficientFunds; // 创建条件对象
        
      /**
         * 构造方法
         * @param n 账户的总数量
         * @param initialBalabce 账户余额的初始值
         */    public Bank(int n, double initialBalabce){
            accounts = new double[n];
            Arrays.fill(accounts, initialBalabce);
            bankLock = new ReentrantLock();
            sufficientFunds = bankLock.newCondition(); // 获得一个条件对象
        }
        /**
         * 转钱的过程
         * @param from 转出账户的下标
         * @param to 装入账户的下标
         * @param amount 转入的金额
         * @throws InterruptedException
         */
        public void transfer(int from, int to, double amount) throws InterruptedException{
            bankLock.lock(); // 加锁
            try {
                while(accounts[from] < amount) // 余额不足时
                    sufficientFunds.await(); // 等待
                System.out.print(Thread.currentThread());
                accounts[from] -= amount;
                System.out.printf(" %10.2f from %d to %d", amount, from, to);
                accounts[to] += amount;
                System.out.printf(" Total Balance: %10.2f%n", getTotalBanlance());
                sufficientFunds.signalAll(); // 唤醒所有的等待线程
            } finally {
                bankLock.unlock(); // 释放锁
            }
        }
        /**
         * 获取总金额的方法
         * @return 总金额
         */
        public double getTotalBanlance(){
            bankLock.lock(); // 加锁
            try {
                double sum = 0;
                for(double d : accounts){
                    sum += d;
                }
                return sum;
            } finally {
                bankLock.unlock(); // 释放锁
            }
        }
        
        public int size(){
            return accounts.length;
        }
    }
    测试方法:
    public class SynchBankTest {
        public static final int NACCOUNTS = 100; // 100个账户
        public static final double INITIAL_BANANCE = 1000; // 初始值1000
        public static final double MAX_AMOUNT = 1000; // 最大的转钱金额
        public static final int DELAY = 10; // 睡眠最大时间
        public static void main(String[] args) {
            Bank bank = new Bank(NACCOUNTS, INITIAL_BANANCE);
            for(int i = 0; i < NACCOUNTS; i++){
                int fromAccount = i;
                Runnable r = () ->{ // 多线程
                    try {
                        while(true){
                            int toAccount = (int)(bank.size() * Math.random());
                            double amount = MAX_AMOUNT * Math.random();
                            bank.transfer(fromAccount, toAccount, amount);
                            Thread.sleep((int)(DELAY * Math.random()));
                        }
                    } catch (Exception e) {
                        // TODO: handle exception
                    }
                    
                };
                Thread t = new Thread(r);
                t.start();
            }     
        }
    }
      [2].使用synchronized关键字(有两种方式:同步方法和同步代码块,这使用同步方法,同步代码块将在下一章的生产消费者例子中展示)
    package book_14.synch;

    import java.util.Arrays;
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;

    /**
     * 同步(使用synchronized):
     *         同步代码块和同步方法.
     */
    public class Bank2 {
        
        private final double[] accounts; // 账户数量
        
        public Bank2(int n, double initialBalabce){
            accounts = new double[n];
            Arrays.fill(accounts, initialBalabce); // 为每个账户赋值
        }
        // 使用synchronized关键字
        public synchronized void transfer(int from, int to, double amount) throws InterruptedException{
            
            while(accounts[from] < amount)
                wait(); // 等待
            System.out.print(Thread.currentThread());
            accounts[from] -= amount;
            System.out.printf(" %10.2f from %d to %d", amount, from, to);
            accounts[to] += amount;
            System.out.printf(" Total Balance: %10.2f%n", getTotalBanlance());
            notifyAll(); // 不要使用notify(),容易造成死锁
            
        }
        // 使用synchronized关键字
        public synchronized double getTotalBanlance(){
            double sum = 0;
            for(double d : accounts){
                sum += d;
            }
            return sum;
        }
        
        public int size(){
            return accounts.length;
        }
    }
    至于测试方法都相同
    当然还有其他的方法,最常用的就这两种

  • 相关阅读:
    Tor网络突破IP封锁,爬虫好搭档【入门手册】
    ubuntu python3相关
    toutiao url
    处理跨域请求
    Python使用虚拟环境
    Python删除文件,空文件夹,非空文件夹
    如何在jupyter中使用Python2和Python3
    推荐使用国内的豆瓣源安装Python插件
    Python数据库查询之组合条件查询-F&Q查询
    获取Django项目的全部url
  • 原文地址:https://www.cnblogs.com/wadmwz/p/7455642.html
Copyright © 2011-2022 走看看