Java从零开始学四十四(多线程)

一、进程与线程

1.1、进程

进程是应用程序的执行实例。

进程是程序的一次动态执行过程,它经历了从代码加载、执行到执行完毕的一个完整过程,这个过程也是进程本身从产生、发展到最终消亡的过程

特征:

动态产生,动态消亡。

进程是并发性的。

进程独立性。是一个独立运行的基本单位,也是系统分配资源和调度的基本单位

1.2、线程

多线程是实现并发机制的一种有效手段。进程和线程一样,都是实现并发的一个基本单位

线程:进程内部的一个执行单元,它是程序中一个单一的顺序控制流程

特点:

  • 线程依赖进程生存
  • 一个进程可以包含多个线程,而一个线程至少要有一个父进程
  • 线程可以有自己的堆栈,程序计数器和局部变量。
  • 线程与父进程的其他线程共享进程所有的全部资源
  • 线程是独立运行,采用抢占方式。
  • 一个线程可以创建和删除别外一具线程
  • 同一个进程中的多个线程之间可以并发执行
  • 线程的调试管理是由进程来完成的。
  • 原则:编程时,必须确保线程不会妨碍同一进程的其他线程

1.3、线程分类

  • 系统级线程:又称核心级线程,负责管理调度不同进程之间的多个线程,由操作系统直接管理
  • 用户级线程:仅存于用户空间,在应用 程序中控制其创建,执行和消亡

1.4、多线程优势

  • 改善用户体验
  • 提高资源的利用率

二、Java中线程的实现

  • 一种是继承Thread类
  • 另一种就是实现Runnable接口

使用步骤:

定义一个线程----创建线程的实例--启动线程--终止线程

2.1、继承Thread类

Thread类是在java.lang包中定义的,一个类只要继承了Thread类,此类就称为多线程操作类。在Thread子类之中,必须明确的覆写Thread类中的run()方法,此方法为线程的主体

/**
 * 继承Thread类重写run方法
 *
 */
public class MyThead1 extends Thread {
    private int count;

    @Override
    public void run() {
        System.out.println("=======线程启动了=======");
        while(this.count<100){
            count++;

        }
        System.out.println("count最终的值:"+count);
    }

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }

}

测试类

/**
 * 测试类
 * MyTheadDemo
 * 继承Thread类创建线程
 * 1.继承Thread类
 * 2.重写run方法
 * 3.实例化线程类对象
 * 4.调用start方法启动线程
 *
 * 继承Thread类存在问题
 * Java中是单继承的,线程类不能继承其它的类
 *
 * 解决办法:实现Runnable接口
 *
 */
public class MyTheadDemo1 {

    public static void main(String[] args) {
        //实例化线程类对象
        MyThead1 myThead1=new MyThead1();
        //启动线程
        myThead1.start();
        /*
         * start方法的作用
         * 该方法公使操作系统初始化一个新的线程
         * 由这个新线程来执行线程对象的Run方法
         */

    }

}

2.2、实现Runnable接口(推荐使用,使用接口可以解决Java中单继承的问题)

在Java中也可以通过实现Runnable接口的方式实现多线程,Runnable接口中只定义了一个抽象方法:

public void run() ;

/**
 * 实现Runnable接口
 *
 */
public class MyRunnable implements Runnable {
    private int count;

    @Override
    public void run() {
        System.out.println("=======线程启动了=======");
        while(this.count<100){
            count++;

        }
        System.out.println("count最终的值:"+count);
    }

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }

}

测试类

/**
 * 测试类
 * MyRunnable
 * 实现Runnable接口创建线程
 * 1.实现Runnable接口
 * 2.实现run方法
 * 3.实例化线程类对象
 * 4.创建Thread类实例对象,并将实例化的线程对象传入
 * 5.调用Thread类实例对象的start方法启动线程
 *
 */
public class MyRunnableDemo {

    public static void main(String[] args) {
        //实例化线程类对象
        Runnable myRunnable=new MyRunnable();
        Thread thread=new Thread(myRunnable);
        //或者Thread thread=new Thread(new MyRunnable());
        //启动线程
        thread.start();

    }

}

2.3、启动线程

  • 继承Thread类启动线程方法:

如果要想正确的启动线程,是不能直接调用run()方法的,应该调用从Thread类中继承而来的start()方法,才可以启动线程

  • 实现Runnable接口启动线程方法:

实际上此时,还是要依靠Thread类完成启动,在Thread类中提供了以下的两个构造方法:

public Thread(Runnable target)

public Thread(Runnable target,String name)

2.4、Thread类和Runnable接口的区别

Thread类和Runnable接口之间在使用上也是有所区别的,如果一个类继承Thread类,则不适合于多个线程共享资源,而实现了Runnable接口,则可以方便的实现资源的共享。

/**
 * 实现Runnable接口
 *
 */
public class MyRunnable implements Runnable {
    private int count;

    @Override
    public void run() {
            count++;

        System.out.println("count最终的值:"+count);
    }

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }

}

测试类

/**
 * 测试类
 * MyRunnable
 * 实现Runnable接口创建线程
 * 1.实现Runnable接口
 * 2.实现run方法
 * 3.实例化线程类对象
 * 4.创建Thread类实例对象,并将实例化的线程对象传入
 * 5.调用Thread类实例对象的start方法启动线程
 *
 */
public class MyRunnableDemo {

    public static void main(String[] args) {
        //实例化线程类对象
        Runnable myRunnable=new MyRunnable();
        Thread thread=new Thread(myRunnable);
        Thread thread2=new Thread(myRunnable);
        //或者Thread thread=new Thread(new MyRunnable());
        //启动线程
        System.out.println("线程1启动");
        thread.start();

        System.out.println("线程2启动");
        thread2.start();

    }

}

结果:

线程1启动
线程2启动
count最终的值:1
count最终的值:2

再看下thread方式

/**
 * 继承Thread类重写run方法
 *
 */
public class MyThead1 extends Thread {
    private int count;

    @Override
    public void run() {

            count++;
        System.out.println("count最终的值:"+count);
    }

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }

}
/**
 * 测试类
 * MyTheadDemo
 * 实现Runnable接口创建纯种
 * 1.实现Runnable接口
 * 2.重写run方法
 * 3.实例化线程类对象
 * 4.调用start方法启动线程
 *
 * 继承Thread类存在问题
 * Java中是单继承的,线程类不能继承其它的类
 *
 * 解决办法:实现Runnable接口
 *
 */
public class MyTheadDemo1 {

    public static void main(String[] args) {
        //实例化线程类对象
        MyThead1 myThead1=new MyThead1();
        MyThead1 myThead2=new MyThead1();
        //启动线程
        System.out.println("线程1启动");
        myThead1.start();
        System.out.println("线程2启动");
        myThead2.start();
        /*
         * start方法的作用
         * 该方法公使操作系统初始化一个新的线程
         * 由这个新线程来执行线程对象的Run方法
         */

    }

}

结果:

线程1启动
线程2启动
count最终的值:1
count最终的值:1

三、线程的状态

要想实现多线程,必须在主线程中创建新的线程对象。任何线程一般具有五种状态,即创建、就绪、运行、阻塞、终止。

四、线程的优先级和方法

4.1、线程的优先级

  • 默认情况下,一个线程继承其父类的优先级
  • 优先级表示为一个整数值
  • 优先级越高,执行的机会越大,反之,执行的机会就越小
  • 高优先级的线程可以抢占低优先级线程的CPU资源
  • 线程的优先级与线程执行的效率没有必然的联系

4.2、线程的方法


No.

方法名称

类型

描述

1

public Thread(Runnable target)

构造

接收Runnable接口子类对象,实例化Thread对象

2

public Thread(Runnable target,String name)

构造

接收Runnable接口子类对象,实例化Thread对象,并设置线程名称

3

public Thread(String name)

构造

实例化Thread对象,并设置线程名称

4

public static Thread currentThread()

普通

返回目前正在执行的线程

5

public final String getName()

普通

返回线程的名称

6

public final int getPriority()

普通

发挥线程的优先级

7

public boolean isInterrupted()

普通

判断目前线程是否被中断,如果是,返回true,否则返回false

8

public final boolean isAlive()

普通

判断线程是否在活动,如果是,返回true,否则返回false

9

public final void join() throws InterruptedException

普通

等待线程死亡

10

public final synchronized void join(long millis) throws InterruptedException

普通

等待millis毫秒后,线程死亡

11

public void run()

普通

执行线程

12

public final void setName(String name)

普通

设定线程名称

13

public final void setPriority(int newPriority)

普通

设定线程的优先值

14

public static void sleep(long millis) throws InterruptedException

普通

使目前正在执行的线程休眠millis毫秒

15

public void start()

普通

开始执行线程

16

public static void yield()

普通

将目前正在执行的线程暂停,允许其它线程执行

17

public final void setDaemon(boolean on)

普通

将一个线程设置成后台运行

18

public final void setPriority(int newPriority)

普通

更改线程的优先级

五、线程调度

5.1、join()方法

作用:阻塞指定的线程等到另一个线程完成以后,再继续执行

package thead;
/**
 * 实现join方法
 * 1.join的线程运行完成后,才会继承运行当前线程
 * 2.join之前要先启动线程start方法
 *
 */
public class JoinRunnable implements Runnable {

    @Override
    public void run() {
        for (int i = 0; i <5; i++) {
            System.out.println(Thread.currentThread().getName()+"  第"+i+"次");
        }

    }

    public static void main(String[] args) {
        //主线程
        for (int i = 0; i <10; i++) {
            if(i==5){
                Thread thread=new Thread(new JoinRunnable());;
                thread.setName("半路切入的线程:");
                try {
                    //启动线程
                    thread.start();
                    //半路加入线程
                    thread.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName()+"   第"+i+"次");
        }
    }

}

结果:

main   第0次
main   第1次
main   第2次
main   第3次
main   第4次
半路切入的线程:  第0次
半路切入的线程:  第1次
半路切入的线程:  第2次
半路切入的线程:  第3次
半路切入的线程:  第4次
main   第5次
main   第6次
main   第7次
main   第8次
main   第9次

5.2、sleep()

阻塞当前线程,当前等待的线程将获得机会

调用sleep方法后,,当前线程会被扶起(暂停执行)当前线程会释放资源

package thead;

public class SleepRunnable implements Runnable {

    @Override
    public void run() {
        try {
            for (int i = 0; i < 10; i++) {

                //每一秒执行一次
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName()+i);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

    public static void main(String[] args) {
        Thread sleepThread=new Thread(new SleepRunnable());
        sleepThread.setName("等待中的线程");
        sleepThread.start();
        for (int i = 0; i < 10; i++) {
            if(i==5){
                try {
                    //主线程=等5秒
                    Thread.sleep(5000);

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName()+i);
        }

        }

    }

结果:

main0
main1
main2
main3
main4
等待中的线程0
等待中的线程1
等待中的线程2
等待中的线程3
main5
main6
main7
main8
main9
等待中的线程4
等待中的线程5
等待中的线程6
等待中的线程7
等待中的线程8
等待中的线程9

5.3、yield()方法

将当前线程转入可运行状态,

package yield;
/**
 * 线程一
 *
 */
public class MyThread1 implements Runnable {

    @Override
    public void run() {
        for (int i = 0; i <10; i++) {
            Thread.yield();
            System.out.println(Thread.currentThread().getName()+":"+i);
        }

    }

}

package yield;
/**
 * 线程二
 *
 */
public class MyThread2 implements Runnable {

    @Override
    public void run() {
        for (int i = 0; i <10; i++) {
            Thread.yield();
            System.out.println(Thread.currentThread().getName()+": "+i);
        }

    }

}

package yield;
/**
 * yield方法使用
 *2个线程抢占方式
 */
public class Test {

    public static void main(String[] args) {
        Thread myThread1=new Thread(new MyThread1());
        myThread1.setName("线程1");
        Thread myThread2=new Thread(new MyThread2());
        myThread2.setName("线程2");
        //同时启动2个线程
        myThread1.start();
        myThread2.start();
    }

}

结果:

线程2: 0
线程1:0
线程2: 1
线程1:1
线程2: 2
线程1:2
线程2: 3
线程1:3
线程1:4
线程2: 4
线程1:5
线程1:6
线程1:7
线程1:8
线程1:9
线程2: 5
线程2: 6
线程2: 7
线程2: 8
线程2: 9

 sleep()和yield()方法比较

  • sleep()方法使当前线程转入被阻塞的状态,而yield()方法使用当前线程转入可运行状态
  • sleep()方法总是强制当前线程停止执行,百yield() 方法不一定
  • sleep()方法可以使其它等待运行的线程有同样的执行级别而yield()方法只使相同或者更高优先级的线程获得执行机会
  • 使用sleep()方法时需要捕获异常,而yield()方法无需要捕获异常

5.4、setDaemon()方法

将线程设置 为后台线程(守护线程)。

只能在线程启动之前设置.

package thead;

public class Daemon implements Runnable {

    @Override
    public void run() {
    for (int i = 0; i <10; i++) {
        System.out.println(Thread.currentThread().getName()+":"+i);
    }

    }

    public static void main(String[] args) {
        Thread daemon=new Thread(new Daemon());
        daemon.setName("后台线程");
        // 设置为后台线程
        daemon.setDaemon(true);
        daemon.start();
        for (int i = 0; i <10; i++) {
            System.out.println(Thread.currentThread().getName()+":"+i);
        }

    }

}

六、同步

一个多线程的程序,如果是通过Runnable接口实现的,则意味着类中的属性将被多个线程共享,那么这样一来就会造成一种问题,如果这多个线程要操作同一资源的时候就有可能出现资源的同步问题。例如:以之前的卖票程序来讲,如果多个线程同时操作的时候就有可能出现卖出票为负数的问题。

问题的解决

如果想解决这样的问题,就必须使用同步,所谓的同步就是指多个操作在同一个时间段内只能有一个线程进行,其他线程要等待此线程完成之后才可以继续执行

解决资源共享的同步操作,可以使用同步代码块和同步方法两种方式完成

同步代码块

在代码块上加上“synchronized”关键字的话,则此代码块就称为同步代码块。

同步方法

除了可以将需要的代码设置成同步代码块之外,也可以使用synchronized关键字将一个方法声明成同步方法。

同步方法定义格式:

synchronized 方法返回值 方法名称(参数列表){}

6.1、简单例子

同一账户2个人同时取款

package demo;

public class Account {

    //余额
    private int balance=500;
    //检查余额

    public int getBalance() {
        return balance;
    }

    //取款
    public void withDraw(int amount){
        balance=balance-amount;
    }

    public void setBalance(int balance) {
        this.balance = balance;
    }

}

package demo;

public class TestAccount implements Runnable{
    private Account account=new Account();

    @Override
    public void run() {
    for (int i = 0; i <5; i++) {
        //一次取走100
        makeWithDraw(100);
        if(account.getBalance()<0){
            System.out.println("账户透支了!!!!!");
        }

    }

    }
    //取款参数  同步方法
    private synchronized void makeWithDraw(int amount){
        if(account.getBalance()>=amount){
            //当前余额是否足够可以取款
            System.out.println(Thread.currentThread().getName()+"  准备取款");
            try {
                //0.5秒后取款
                Thread.sleep(500);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            //完成取款
            account.withDraw(amount);
            System.out.println(Thread.currentThread().getName()+"  完成取款,当前余额为: "+account.getBalance());

        }else{
            //如果余额不足不能取款
            System.out.println(Thread.currentThread().getName()+"  余额不足以支付当前取款, 余额为:  "
                    +account.getBalance());
        }
    }

}

测试类

package demo;
/**
 * 如果一个资源被多个线程使用,不上锁就会造成读取严重错误
 * 如果想让当前资源被一个线程使用时,不会受到其他纯种的影响,应该给当前资源上锁
 * Java中使用sychronized关键字保证数据同步
 *
 */
public class Test {

    public static void main(String[] args) {
        //创建线程类的实例
        TestAccount ta=new TestAccount();
        //创建线程
        Thread thread1=new Thread(ta);
        thread1.setName("张三");
        Thread thread2=new Thread(ta);
        thread2.setName("张三的妻子");
        //启动线程
        thread1.start();
        thread2.start();
    }

}

上面是同步方法

下面是同步代码块

package demo;

public class TestAccount implements Runnable{
    private Account account=new Account();

    @Override
    public void run() {
    for (int i = 0; i <5; i++) {
        //一次取走100
        makeWithDraw(100);
        if(account.getBalance()<0){
            System.out.println("账户透支了!!!!!");
        }

    }

    }
    //取款参数
    private  void makeWithDraw(int amount){
        //同步代码块
        synchronized (account){
        if(account.getBalance()>=amount){
            //当前余额是否足够可以取款
            System.out.println(Thread.currentThread().getName()+"  准备取款");
            try {
                //0.5秒后取款
                Thread.sleep(500);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            //完成取款
            account.withDraw(amount);
            System.out.println(Thread.currentThread().getName()+"  完成取款,当前余额为: "+account.getBalance());

        }else{
            //如果余额不足不能取款
            System.out.println(Thread.currentThread().getName()+"  余额不足以支付当前取款, 余额为:  "
                    +account.getBalance());
        }
    }
    }

}

七、线程间通信的实现

  • wait()方法:
  • notify()方法:
  • notifyAll()方法:

以上3个方法只能在同步方式或者同步代码块中使用

wait()方法:会挂起当前的线程,并且释放共享资源的锁。当前线程会从可运行状态转为阻塞状态直到调用了wait()方法所属的那个对象的notify()方法或者notifyAll()方法.

notify()方法:可以唤醒因为调用wait()方法而被挂起的那个线程,并且使这个线程退出阻塞状态进入可运行状态

notifyAll()方法:可以唤醒因为所有调用wait()方法而被挂起的那个线程,并且使这些线程退出阻塞状态进入可运行状态

生产者和消费者

package com.pb;
/**
 * 商品共享数据
 *
 */
public class SharedData {

    private char c;
    private boolean idProducted=false;//信号量
    //同步方法生产者生产产品的的方法
    public synchronized void putSharedChar(char c){
        //如果产品还没有被消费,则生产都等待
        if(idProducted){
            try {
                System.out.println("消费者还未消费,因此生产都停止生产");
                wait();
            } catch (InterruptedException e) {

                e.printStackTrace();
            }
        }
        this.c=c;
        idProducted=true;  //标记已经生产
        notify();//通知消费都
        System.out.println("生产者生产了产品"+c+",通知消费者");
    }
    //同步方法   消费者消费产品的的方法
        public synchronized char getSharedChar(char c){
            //如果产品还没有被消费,则生产都等待
            if(idProducted==false){
                try {
                    System.out.println("生产者还未生产,消费者停止消费");
                    wait();
                } catch (InterruptedException e) {

                    e.printStackTrace();
                }
            }

            idProducted=false;  //标记已经消费
            notify();//通知生产者
            System.out.println("消费者消费了产品"+c+",通知生产者");
            return this.c;

        }
}
package com.pb;
/**
 * 生产者
 *
 */
public class Producer implements Runnable {
    //共享数据
    private SharedData sharedData;

    public Producer(SharedData sharedData){
        this.sharedData=sharedData;
    }

    @Override
    public void run() {
        for (char c = ‘A‘; c <= ‘D‘; c++) {

            try {
                Thread.sleep((int)Math.random()*3000);

            } catch (InterruptedException e) {

                e.printStackTrace();
            }
            //将产品生产后,放入仓库
            sharedData.putSharedChar(c);
        }

    }

}
package com.pb;
/**
 * 消费者
 *
 */
public class Consumer implements Runnable {
    //共享数据
        private SharedData sharedData;

        public Consumer(SharedData sharedData){
            this.sharedData=sharedData;
        }
    @Override
    public void run() {
        char ch = 0;
        do {
            try {
                Thread.sleep((int)Math.random()*3000);

            } catch (InterruptedException e) {

                e.printStackTrace();
            }
            //从仓库中取中产品
            ch=sharedData.getSharedChar(ch);
        } while (ch!=‘D‘);

    }

}

测试类

package com.pb;

public class CommunicationDemo {

    public static void main(String[] args) {
        //共享资源,产品
        SharedData sharedData=new SharedData();
        Thread producer=new Thread(new Producer(sharedData));
        Thread consumer=new Thread(new Consumer(sharedData));

        //启动线程
        consumer.start();
        producer.start();

    }

}

结果:

生产者还未生产,消费者停止消费
生产者生产了产品A,通知消费者
消费者消费了产品A,通知生产者
生产者生产了产品B,通知消费者
生产者还未生产,消费者停止消费
生产者生产了产品C,通知消费者
消费者消费了产品B,通知生产者
生产者生产了产品D,通知消费者
消费者消费了产品C,通知生产者
时间: 2024-12-20 16:03:54

Java从零开始学四十四(多线程)的相关文章

Java从零开始学二十二(集合Set接口)

一.Set接口的定义 Set接口也是Collection接口的子接口,但是与Collection或List接口不同的是,Set接口中不能加入重复的元素 Set接口的主要方法与Collection是一致的 Set接口的实例无法像List接口那样进行双向输出.不存在get方法使用Iterator接口来遍历集合 2个常用方法:hasNext方法表示判断是否还有元素可以迭代 next()方法:返回迭代的下一个元素 Set接口的常用子类 散列存放:HashSet 有序存放:TreeSet 二.使用SetH

Java从零开始学三十二(正则表达式)

一.为什么要有正则 正则表达式可以方便的对数据进行匹配,可以执行更加复杂的字符串验证.拆份.替换功能. 例如:现在要求判断一个字符串是否由数字组成,则可以有以下的两种做法: 不使用正则完成 使用正则完成 二.Pattern.Matcher类 如果要想在程序中应用正则表达式则必须依靠Pattern类与Matcher类,这两个类都在java.util.regex包中定义.Pattern类的主要作用是进行正则规范的编写,而Matcher类主要是执行规范,验证一个字符串是否符合其规范. 常用正则规则 N

Java从零开始学三十(String和StringBuffer类)

一.StringBuffer连接字符操作 当一个字符串的内容需要被经常改变时就要使用StringBuffer 在StringBuffer中使用append()方法,完成字符串的连接操作 二.StringBuffer类的常用方法 No. 方法定义 类型 描述 1 public StringBuffer() 构造 StringBuffer的构造方法 2 public StringBuffer append(char c) 方法 在StringBuffer中提供了大量的追加操作(与String中使用“

Java从零开始学二十四点(集合工具类Collections)

一.Collections简介 在集合的应用开发中,集合的若干接口和若干个子类是最最常使用的,但是在JDK中提供了一种集合操作的工具类 —— Collections,可以直接通过此类方便的操作集合 二.Collections类的常用方法及常量 No. 方法 类型 描述 1 public static final List EMPTY_LIST 常量 返回一个空的List集合 2 public static final Set EMPTY_SET 常量 返回空的Set集合 3 public sta

Java从零开始学二十(集合简介)

一.为什么需要集合框架 数组的长度是固定的,但是如果写程序时并不知道程序运行时会需要多少对象.或者需要更复杂的方式存储对象,---那么,可以使用JAVA集合框架,来解决这类问题 二.集合框架主要接口 No 接口 描述 1 Collection 是存放一组单值的最大接口,所谓的单值是指集合中的每个元素都是一个对象.一般很少会直接使用此接口直接操作. 2 List 是Collection接口的子接口,也是最常用的接口,此接口对Collection接口进行了大量的扩充,里面的内容是允许重复的. 3 S

Java从零开始学三十三四(JAVA IO-流简述)

一.流概念(stream) File类并不能对文件内容进行读写. 读文件就是指:把文件的内中的数据读取到内存中来 写文件就是指:把内存中的数据写入到文件中去. 通过什么读写文件呢?文件流. 1.1.流概念 一连串流动的字符 1.2.流的特性 先进先出的方式传递信息 一个字节序列 具有方向性:输入流.输出流 二.按照流向划分 输入流:读取数据--InputStream和Reader作为基类 输出流:写入数据--OutputStream和Writer作为基类 一共四个4基类. 其中InputStre

Java从零开始学三十五(JAVA IO- 字节流)

一.字节流 FileOutputStream是OutputStream 的直接子类 FileInputStream也是InputStream的直接子类 二.文本文件的读写 2.1.字节输入流 Test.txt文件内容 abcdefg package com.pb.io; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOExcept

Java从零开始学二十九(大数操作(BigIntger、BigDecimal)

一.BigInteger 如果在操作的时候一个整型数据已经超过了整数的最大类型长度long的话,则此数据就无法装入,所以,此时要使用BigInteger类进行操作. 不可变的任意精度的整数.所有操作中,都以二进制补码形式表示 BigInteger(如 Java 的基本整数类型).BigInteger 提供所有 Java 的基本整数操作符的对应物,并提供 java.lang.Math 的所有相关方法.另外,BigInteger 还提供以下运算:模算术.GCD 计算.质数测试.素数生成.位操作以及一

Java从零开始学二十八(Math类和Random类)

一.Math概述 提供了常用的数学运算方法和两个静态常量E(自然对数的底数)和PI(圆周率) 二.常用方法 package com.pb.demo1; public class MathTest { public static void main(String[] args) { System.out.println("求平方根:" + Math.sqrt(9.0)); System.out.println("求两数的最大值:" + Math.max(10,30))

Java从零开始学三十六(JAVA IO- 字符流)

一.字符流 BufferedReader:BufferedReader是从缓冲区之中读取内容,所有的输入的字节数据都将放在缓冲区之中 BufferedWriter:把一批数据写入到缓冲区,当缓冲区区的满时,再把缓冲区的内容写到字符输出流中 二.对文本文件的读写 2.1.字符输入流 2.2.字符输出流 2.3.综合使用 package com.pb.io.buffered; import java.io.BufferedReader; import java.io.BufferedWriter;