Java基础之多线程
2021/10/20 11:09:43
本文主要是介绍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基础之多线程的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-10-01基于Python+Vue开发的医院门诊预约挂号系统
- 2024-10-01基于Python+Vue开发的旅游景区管理系统
- 2024-10-01RestfulAPI入门指南:打造简单易懂的API接口
- 2024-10-01初学者指南:了解和使用Server Action
- 2024-10-01Server Component入门指南:搭建与配置详解
- 2024-10-01React 中使用 useRequest 实现数据请求
- 2024-10-01使用 golang 将ETH账户的资产平均分散到其他账户
- 2024-10-01JWT用户校验课程:从入门到实践
- 2024-10-01Server Component课程入门指南
- 2024-09-30Dnd-Kit学习:新手快速入门指南