Java教程

Java基础之多线程

本文主要是介绍Java基础之多线程,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

程序、进程、线程

  • 程序(program):静态代码
  • 进程(process):程序的一次执行过程,或是一个正在运行中的程序
  • 线程(thread):进程可以进一步细化为线程,是一个程序内部的一条执行路径

创建线程的4种方式

继承Thread类

public class ThreadTest {
    public static void main(String[] args) {
        new EvenPrinter().start();
        new EvenPrinter().start();
    }
}

/**
 * 打印100以内的偶数
 */
class EvenPrinter extends Thread {
    @Override
    public void run() {
        for (int i = 1; i <= 100; i++) {
            if (i % 2 == 0) {
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
        }
    }
}

实现Runnable接口

public class ThreadTest {
    public static void main(String[] args) {
        OddPrinter oddPrinter = new OddPrinter();
        new Thread(oddPrinter).start();
        new Thread(oddPrinter).start();
        new Thread(oddPrinter).start();
    }
}

/**
 * 打印100以内的奇数
 */
class OddPrinter implements Runnable {
    @Override
    public void run() {
        for (int i = 1; i <= 100; i++) {
            if (i % 2 != 0) {
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
        }
    }
}

实现Callable接口

与实现Runnable接口相比,实现Callable这种方式:

  • 可以接收返回值
  • 支持泛型
  • 可抛出异常
public class ThreadTest {
    public static void main(String[] args) {
        NumberPrinter numberPrinter = new NumberPrinter();
        FutureTask<Integer> task = new FutureTask<>(numberPrinter);
        new Thread(task).start();
        Integer sum = null;
        try {
            sum = task.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        System.out.println("sum=" + sum);
    }
}

/**
 * 打印100以内的数字,并返回其和
 */
class NumberPrinter implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        int sum = 0;
        for (int i = 1; i <= 100; i++) {
            System.out.println(Thread.currentThread().getName() + ":" + i);
            sum += i;
        }
        return sum;
    }
}

使用线程池

public class ThreadTest {
    public static void main(String[] args) {
        // 创建一个包含10个线程的线程池
        ExecutorService service = Executors.newFixedThreadPool(10);

        // void execute(Runnable command)
        service.execute(new OddPrinter());
        service.execute(new EvenPrinter());

        // <T> Future<T> submit(Callable<T> task)
        Future<Integer> future = service.submit(new NumberPrinter());
        Integer sum = 0;
        try {
            sum = future.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        System.out.println("sum=" + sum);

        // 关闭线程池
        service.shutdown();
    }
}

/**
 * 打印100以内的数字,并返回其和
 */
class NumberPrinter implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        int sum = 0;
        for (int i = 1; i <= 100; i++) {
            System.out.println(Thread.currentThread().getName() + ":" + i);
            sum += i;
        }
        return sum;
    }
}

/**
 * 打印100以内的奇数
 */
class OddPrinter implements Runnable {
    @Override
    public void run() {
        for (int i = 1; i <= 100; i++) {
            if (i % 2 != 0) {
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
        }
    }
}

/**
 * 打印100以内的偶数
 */
class EvenPrinter extends Thread {
    @Override
    public void run() {
        for (int i = 1; i <= 100; i++) {
            if (i % 2 == 0) {
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
        }
    }
}

Thread类常用方法

  • void start():启动线程,执行run()方法
  • void run():线程在被调度时执行的操作
  • String getName()
  • void setName(String name)
  • static Thread currentThread():返回当前线程
  • static void yeid():线程让步,把执行机会让给其他线程
  • void join():在线程a中调用线程b的join()方法,等线程b执行完毕后,继续执行线程a
  • static void sleep(long millis):让当前线程休眠指定的毫秒数
  • boolean isAlive():线程是否存活
public class ThreadTest {
    public static void main(String[] args) {
        OddPrinter oddPrinter = new OddPrinter();
        Thread t1 = new Thread(oddPrinter);
        // 设置线程名称
        t1.setName("线程t1");
        // 启动线程t1
        t1.start();
        // 等待线程t1执行完毕后,再继续执行后面的代码
        try {
            t1.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 线程的状态(生命周期)
        System.out.println("t1.getState():" + t1.getState());
        // 线程是否存活
        System.out.println("t1.isAlive():" + t1.isAlive());
    }
}

/**
 * 打印100以内的奇数
 */
class OddPrinter implements Runnable {
    @Override
    public void run() {
        for (int i = 1; i <= 100; i++) {
            if (i % 2 != 0) {
                // 让当前线程休眠100毫秒
                try {
                    Thread.currentThread().sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
        }
    }
}

线程的生命周期

线程同步

使用synchronized代码块解决Runnable接口实现类的线程安全问题

public class TicketWindowTest {
    public static void main(String[] args) {
        TicketWindow ticketWindow = new TicketWindow();
        new Thread(ticketWindow, "窗口1").start();
        new Thread(ticketWindow, "窗口2").start();
        new Thread(ticketWindow, "窗口3").start();
    }
}

/**
 * 售票窗口
 */
class TicketWindow implements Runnable {
    // 总共100张票
    private int ticket = 100;

    @Override
    public void run() {
        while (true) {
            // 使用this作为同步监视器(锁)
            synchronized (this) {
                if (ticket > 0) {
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + ":" + ticket--);
                } else {
                    break;
                }
            }
        }
    }
}

使用synchronized代码块解决Thread子类的线程安全问题

public class TicketWindowTest {
    public static void main(String[] args) {
        new TicketWindow().start();
        new TicketWindow().start();
        new TicketWindow().start();
    }
}

/**
 * 售票窗口
 */
class TicketWindow extends Thread {
    // 总共100张票
    private static int ticket = 100;

    @Override
    public void run() {
        while (true) {
            // 使用TicketWindow.class作为同步监视器(锁)
            synchronized (TicketWindow.class) {
                if (ticket > 0) {
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + ":" + ticket--);
                } else {
                    break;
                }
            }
        }
    }
}

使用synchronized方法解决Runnable接口实现类的线程安全问题

public class TicketWindowTest {
    public static void main(String[] args) {
        TicketWindow ticketWindow = new TicketWindow();
        new Thread(ticketWindow, "窗口1").start();
        new Thread(ticketWindow, "窗口2").start();
        new Thread(ticketWindow, "窗口3").start();
    }
}

/**
 * 售票窗口
 */
class TicketWindow implements Runnable {
    // 总共100张票
    private int ticket = 100;

    @Override
    public void run() {
        while (ticket > 0) {
            sale();
        }
    }

    /**
     * sale方法不是静态的,将使用this作为同步监视器
     */
    private synchronized void sale() {
        if (ticket > 0) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + ":" + ticket--);
        }
    }
}

使用synchronized方法解决Thread子类的线程安全问题

public class TicketWindowTest {
    public static void main(String[] args) {
        new TicketWindow().start();
        new TicketWindow().start();
        new TicketWindow().start();
    }
}

/**
 * 售票窗口
 */
class TicketWindow extends Thread {
    // 总共100张票
    private static int ticket = 100;

    @Override
    public void run() {
        while (ticket > 0) {
            sale();
        }
    }

    /**
     * sale方法是静态的,将使用TicketWindow.class作为同步监视器
     */
    private static synchronized void sale() {
        if (ticket > 0) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + ":" + ticket--);
        }
    }
}

使用Lock接口手动开关锁

public class TicketWindowTest {
    public static void main(String[] args) {
        TicketWindow ticketWindow = new TicketWindow();
        new Thread(ticketWindow, "窗口1").start();
        new Thread(ticketWindow, "窗口2").start();
        new Thread(ticketWindow, "窗口3").start();
    }
}

/**
 * 售票窗口
 */
class TicketWindow implements Runnable {
    // 总共100张票
    private int ticket = 100;
    // 同步监视器
    private ReentrantLock lock = new ReentrantLock(true);

    @Override
    public void run() {
        while (ticket > 0) {
            lock.lock();
            if (ticket > 0) {
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + ":" + ticket--);
            }
            lock.unlock();
        }
    }
}

线程通信

三个方法:

  • wait(): 令当前线程挂起并放弃CPU、同步资源并等待,使别的线程可访问并修改共享资源
  • notify():唤醒正在排队等待同步资源的线程中优先级最高者结束等待
  • notifyAll():唤醒正在排队等待资源的所有线程结束等待

注意点:

  • 以上三个方法声明在Object类中
  • 以上三个方法只能在在synchronized方法或synchronized代码块中才能使用
public class CommTest {
    public static void main(String[] args) {
        // 两个线程将交替打印
        NumberPrinter numberPrinter = new NumberPrinter();
        new Thread(numberPrinter).start();
        new Thread(numberPrinter).start();
    }
}

/**
 * 打印1~100
 */
class NumberPrinter implements Runnable {
    private int i = 1;
    @Override
    public void run() {
        while (true) {
            synchronized (this) {
                if (i <= 100) {
                    // 唤醒一个线程
                    notify();
                    System.out.println(Thread.currentThread().getName() + ":" + i++);
                    // 休眠当前线程
                    try {
                        wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } else {
                    // 唤醒所有线程,否则程序无法自动退出
                    notifyAll();
                    break;
                }
            }
        }
    }
}
这篇关于Java基础之多线程的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!