多线程
并发与并行
-
并发:指两个或多个事件在同一个时间段内发生。
-
并行:指两个或多个事件在同一时刻发生(同时发生)。
-
当系统只有一个CPU时,线程会以某种顺序执行多个线程,我们把这种情况称之为 线程调度。
线程与进程
-
进程:
-
是指一个内存中运行的应用程序;
-
每个进程都有一个独立的内存空间,一个应用程序可以同时运行多个进程;
-
-
系统运行一个程序即是一个进程从创建、运行到消亡的过程。
-
-
线程:
-
线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程。
-
一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序。
-
-
简而言之:一个程序运行后至少有一个进程,一个进程中可以包含多个线程。
线程
-
java.lang.Thread 类代表线程
-
自定义创建线程
-
方式一:继承Thread类
-
定义Thread类的子类,并重写该类的run()方法。
-
run()方法的方法体就是线程需要完成的任务。
-
创建Thread子类的实例,即创建了线程对象。
-
调用线程对象的start()方法来启动该线程。
-
-
方式二:实现Runnable接口
-
创建一个类实现Runnable接口,并重写该类的run()方法。
-
创建Runnable实现类的实例,调用
public Thread(Runnable target)
方法,将实例作为参数target来创建Thread对象。 -
调用线程对象的start()方法来启动该线程。
-
-
方式三:匿名内部类
Runnable r =new Runnable() { @Override public void run() { } }
-
-
自定义线程名称
public Thread(String name) :分配一个指定名字的新的线程对象。
-
获取线程名称
public String getName() :获取当前线程名称。//方式一的获取方式 public static Thread currentThread() :返回对当前正在执行的线程对象的引用。//方式二的获取方式
线程安全
线程安全
线程安全问题都是由全局变量及静态变量引起的。若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则的话就可能影响线程安全。
线程同步
同步代码块
-
synchronized 关键字可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问。
synchronized(lock){ 需要同步操作的代码 }
同步方法
-
使用synchronized修饰的方法,就叫做同步方法,保证A线程执行该方法的时候,其他线程只能在方法外等着。
public synchronized void method(){ 可能会产生线程安全问题的代码 }
锁机制
-
java.util.concurrent.locks.Lock 机制提供了比synchronized代码块和synchronized方法更广泛的锁定操作。
-
Lock锁也称同步锁,加锁与释放锁方法化了,如下:
public void lock()
:加同步锁。public void unlock()
:释放同步锁。 -
创建Lock锁对象:
Lock lock = new ReentrantLock();
-
在需要同步的代码语句前加上同步锁方法,在结束的地方释放同步锁。
线程状态
案例
- 银行取钱问题
package ThreadDemo; //2.银行取钱模式 // // 两个人AB通过一个账户去银行取钱,A在柜台取钱,B在ATM机取钱。 // 假设账户总共有10000块, A每次从柜台取出100块,休息100毫秒,B每次从ATM机取出200块,休息200毫秒 // 在每次取出钱之后,都展示一下用户取出了多少钱,银行账户还剩多少钱。 // 如此循环往复,直到把账户中的钱取出,结束程序。 public class BankTest { public static void main(String[] args) { Bank bank = new Bank(); userA aa = new userA(bank); userB bb = new userB(bank); new Thread(aa, "用户A").start(); new Thread(bb, "用户B").start(); } } class Bank { private static int Money = 10000; public synchronized void A() { if (Money >= 100) { Money -= 100; System.out.println(Thread.currentThread().getName() + "用户取出了100元,银行账户还剩" + Money + "元"); notify(); } else { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } public synchronized void B() { if (Money >= 200) { Money -= 200; System.out.println(Thread.currentThread().getName() + "用户取出了200元,银行账户还剩" + Money + "元"); notify(); } else { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } class userA extends Thread { private Bank bank; public userA(Bank bank) { this.bank = bank; } @Override public void run() { while (true) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } bank.A(); } } } class userB extends Thread { private Bank bank; public userB(Bank bank) { this.bank = bank; } @Override public void run() { while (true) { try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } bank.B(); } } }